diff --git a/CHANGELOG.md b/CHANGELOG.md index 618d0a4..726b735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how * workspace counter in status bar. +## [2.0.0] + +### Added + +- New Command : `Save the collected language configurations`. + +### Update + +- This extension is no longer resident. + - Don't save whether or not the program is shown in the status bar in the settings. + ## [1.3.5] ### Fixed diff --git a/README.md b/README.md index 61e35fa..4f4af11 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,13 @@ VS Code extension: counts blank lines, comment lines, and physical lines of sour * [github](https://github.com/uctakeoff/vscode-counter) * [Marketplace](https://marketplace.visualstudio.com/items?itemName=uctakeoff.vscode-counter) +## VSCode Counter 2.0 is released! + +* Experimental support for "**VSCode Remove Development**". + + When using VSCode Counter in *VSCode Remove Development*, use the `Save language configurations` function You will need to. + [See below for more information](#save-language-configurations). + ## Features - Count the code lines of source code in workspace or directory. @@ -41,9 +48,25 @@ VS Code extension: counts blank lines, comment lines, and physical lines of sour * Available languages can be increased by adding language extensions. +### Save language configurations + +**VSCode Counter** is able to aggregate in unknown languages by referring to the information in the installed language extensions. However, I found out that **this information is not available in Remote Development**. + +Therefore, VSCode Counter's ability of **collecting VSCode language extensions** is now called as an independent function. The idea is to collect the information once in the local environment and store it so that it can be used remotely. + +* First, launch VSCode on your local server. +* Then, open the command palette and select `VSCodeCounter: Save the collected language configurations`. +* Then *settings.json* will store the configuration information collected from the current language extensions . + ![](images/save_lang.png) +* Connect to the remote and use the VSCodecounter as usual. + + +You can also change the location where your configurations are stored. +However, you must carry the stored information to the remote environment by yourself. + + ## Extension Settings -* `VSCodeCounter.showInStatusBar`: Whether to show the count result of the current file on the status bar in real time. * `VSCodeCounter.useGitignore`: Whether to use '.gitignore' files for excluding files. * `VSCodeCounter.useFilesExclude`: Whether to use setting 'files.exclude' for excluding files. * `VSCodeCounter.printNumberWithCommas`: Whether to print a number with commas as thousands separators.(except for CSV) @@ -56,6 +79,6 @@ VS Code extension: counts blank lines, comment lines, and physical lines of sour * `VSCodeCounter.outputAsCSV`: Whether to output the result as a CSV file. * `VSCodeCounter.outputAsMarkdown`: Whether to output the result as a Markdown file. * `VSCodeCounter.outputPreviewType`: Type of output file to preview after counting. Choose from `text`, `csv`, `markdown` or `none`. -* `VSCodeCounter.blockComment`: Define patterns indicating the beginning and end of the block document(here document). +* `VSCodeCounter.saveLocation`: Specify where to store the collected language configurations. **Enjoy!** diff --git a/images/save_lang.png b/images/save_lang.png new file mode 100644 index 0000000..fbc82ed Binary files /dev/null and b/images/save_lang.png differ diff --git a/package-lock.json b/package-lock.json index df921dd..da1bd9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,42 +1,41 @@ { "name": "vscode-counter", - "version": "1.3.4", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.10.4" } }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", "dev": true, "requires": { + "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", - "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", "dev": true, "requires": { - "@types/events": "*", "@types/minimatch": "*", "@types/node": "*" } @@ -57,21 +56,21 @@ "dev": true }, "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", "dev": true }, "@types/node": { - "version": "12.12.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.6.tgz", - "integrity": "sha512-FjsYUPzEJdGXjwKqSpE0/9QEh6kzhTAeObA54rn6j3rR4C/mzpI9L0KNfoeASSPMMdxIsoJuCLDWcM/rVjIsSA==", + "version": "14.0.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.14.tgz", + "integrity": "sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==", "dev": true }, "@types/vscode": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.40.0.tgz", - "integrity": "sha512-5kEIxL3qVRkwhlMerxO7XuMffa+0LBl+iG2TcRa0NsdoeSFLkt/9hJ02jsi/Kvc6y8OVF2N2P2IHP5S4lWf/5w==", + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.46.0.tgz", + "integrity": "sha512-8m9wPEB2mcRqTWNKs9A9Eqs8DrQZt0qNFO8GkxBOnyW6xR//3s77SoMgb/nY1ctzACsZXwZj3YRTDsn4bAoaUw==", "dev": true }, "agent-base": { @@ -84,9 +83,9 @@ } }, "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, "ansi-regex": { @@ -104,6 +103,16 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -113,11 +122,29 @@ "sprintf-js": "~1.0.2" } }, + "array.prototype.map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", + "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.4" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -127,6 +154,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -167,6 +203,22 @@ } } }, + "chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + } + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -257,9 +309,9 @@ } }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "emoji-regex": { @@ -269,27 +321,49 @@ "dev": true }, "es-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", - "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", + "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", + "dev": true, + "requires": { + "es-abstract": "^1.17.4", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-string": "^1.0.5", + "isarray": "^2.0.5" } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -324,19 +398,23 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "flat": { @@ -354,6 +432,13 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -380,6 +465,15 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -402,9 +496,9 @@ "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, "he": { @@ -466,6 +560,21 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", @@ -473,15 +582,21 @@ "dev": true }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", "dev": true }, "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { @@ -490,30 +605,85 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", "dev": true, "requires": { - "has": "^1.0.1" + "has-symbols": "^1.0.1" } }, + "is-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" } }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", + "dev": true + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dev": true, + "requires": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -531,18 +701,17 @@ } }, "jsonc-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.0.tgz", - "integrity": "sha512-4fLQxW1j/5fWj6p78vAlAafoCKtuBm6ghv+Ij5W2DrDx0qE+ZdEl2c6Ko1mgJNF5ftX1iEWQQ4Ap7+3GlhjkOA==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.0.tgz", + "integrity": "sha512-b0EBt8SWFNnixVdvoR2ZtEGa9ZqLhbJnOjezn+WP+8kspFm+PFYDN8Z4Bc7pRlDjvuVcADSUkroIuTWWn/YiIA==" }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -552,12 +721,12 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, "minimatch": { @@ -569,87 +738,69 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "mocha": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", - "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz", + "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==", "dev": true, "requires": { - "ansi-colors": "3.2.3", + "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", + "chokidar": "3.3.1", "debug": "3.2.6", - "diff": "3.5.0", + "diff": "4.0.2", "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", + "find-up": "4.1.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "log-symbols": "3.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "ms": "2.1.2", "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", + "promise.allsettled": "1.0.2", + "serialize-javascript": "3.0.0", + "strip-json-comments": "3.0.1", + "supports-color": "7.1.0", + "which": "2.0.2", "wide-align": "1.1.3", - "yargs": "13.3.0", - "yargs-parser": "13.1.1", + "workerpool": "6.0.0", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", "yargs-unparser": "1.6.0" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", "dev": true }, "object-keys": { @@ -670,16 +821,6 @@ "object-keys": "^1.0.11" } }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -690,21 +831,21 @@ } }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" } }, "p-try": { @@ -714,9 +855,9 @@ "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-is-absolute": { @@ -731,6 +872,34 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "promise.allsettled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", + "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.1", + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "iterate-value": "^1.0.0" + } + }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -744,9 +913,9 @@ "dev": true }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -767,6 +936,12 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "serialize-javascript": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", + "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", + "dev": true + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -789,24 +964,24 @@ "strip-ansi": "^4.0.0" } }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" } }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" } }, "strip-ansi": { @@ -819,30 +994,47 @@ } }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" } }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", "dev": true }, "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.2.tgz", + "integrity": "sha512-UyNrLdK3E0fQG/xWNqAFAC5ugtFyPO4JJR1KyyfQAyzR8W0fTRrC91A8Wej4BntFzcvETdCSDa/4PnNYJQLYiA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -853,19 +1045,11 @@ "glob": "^7.1.1", "js-yaml": "^3.13.1", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", + "mkdirp": "^0.5.3", "resolve": "^1.3.2", "semver": "^5.3.0", - "tslib": "^1.8.0", + "tslib": "^1.10.0", "tsutils": "^2.29.0" - }, - "dependencies": { - "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", - "dev": true - } } }, "tsutils": { @@ -878,15 +1062,15 @@ } }, "typescript": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", - "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz", + "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==", "dev": true }, "vscode-test": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.2.2.tgz", - "integrity": "sha512-7bF8tINeynZ52Lg8vsJI2mFKnXD0HtVJoOfYzEUhMspo44lPRTcVFSg+PIY3jy8OTd3dMFaxAscBznCvGgdM2g==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz", + "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==", "dev": true, "requires": { "http-proxy-agent": "^2.1.0", @@ -895,9 +1079,9 @@ } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -918,6 +1102,12 @@ "string-width": "^1.0.2 || 2" } }, + "workerpool": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", + "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", + "dev": true + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -970,9 +1160,9 @@ "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { "cliui": "^5.0.0", @@ -984,7 +1174,7 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -993,6 +1183,40 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -1016,9 +1240,9 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/package.json b/package.json index fd59ed0..f1b276b 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,13 @@ "name": "vscode-counter", "displayName": "VS Code Counter", "description": "Count lines of code in many programming languages.", - "version": "1.3.5", + "version": "2.0.0", "publisher": "uctakeoff", "author": { "name": "Ushiyama Kentaro" }, "engines": { - "vscode": "^1.40.0" + "vscode": "^1.46.0" }, "galleryBanner": { "color": "#BF9C68", @@ -26,18 +26,18 @@ "Programming Languages" ], "keywords": [ - "code", "count", - "counter", + "loc", + "code", "step", "line" ], "activationEvents": [ - "*", "onCommand:extension.vscode-counter.countInFile", "onCommand:extension.vscode-counter.countInDirectory", "onCommand:extension.vscode-counter.countInWorkspace", - "onCommand:extension.vscode-counter.outputAvailableLanguages" + "onCommand:extension.vscode-counter.outputAvailableLanguages", + "onCommand:extension.vscode-counter.saveLanguageConfigurations" ], "contributes": { "commands": [ @@ -64,6 +64,12 @@ "category": "VSCodeCounter", "title": "%commands.outputAvailableLanguages.title%", "icon": "icon.png" + }, + { + "command": "extension.vscode-counter.saveLanguageConfigurations", + "category": "VSCodeCounter", + "title": "%commands.saveLanguageConfigurations.title%", + "icon": "icon.png" } ], "menus": { @@ -79,11 +85,6 @@ "type": "object", "title": "VSCode Counter", "properties": { - "VSCodeCounter.showInStatusBar": { - "description": "%configuration.showInStatusBar.description%", - "type": "boolean", - "default": false - }, "VSCodeCounter.useGitignore": { "description": "%configuration.useGitignore.description%", "type": "boolean", @@ -171,72 +172,80 @@ ], "default": "markdown" }, - "VSCodeCounter.blockComment": { - "description": "%configuration.blockComment.description%", - "type": "array", - "items": { - "type": "object", - "properties": { - "types": { - "description": "%configuration.blockComment.types.description%", - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - }, - "patterns": { - "description": "%configuration.blockComment.patterns.description%", - "type": "array", - "items": { + "VSCodeCounter.saveLocation": { + "description": "%configuration.saveLocation.description%", + "type": "string", + "enum": [ + "global settings", + "workspace settings", + "output directory" + ], + "default": "global settings" + }, + "VSCodeCounter.languages": { + "description": "%configuration.languages.description%", + "type": "object", + "default": {}, + "patternProperties": { + ".*": { + "type": "object", + "title": "language configuration", + "properties": { + "aliases": { + "type": "array", + "description": "%configuration.languages.aliases.description%", + "items": { + "type": "string" + } + }, + "filenames": { "type": "array", - "minItems": 2, - "maxItems": 2, + "description": "%configuration.languages.filenames.description%", "items": { "type": "string" } + }, + "extensions": { + "type": "array", + "description": "%configuration.languages.extensions.description%", + "items": { + "type": "string" + } + }, + "lineComments": { + "type": "array", + "description": "%configuration.languages.lineComments.description%", + "items": { + "type": "string" + } + }, + "blockComments": { + "type": "array", + "description": "%configuration.languages.blockComments.description%", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "string" + } + } + }, + "blockStrings": { + "type": "array", + "description": "%configuration.languages.blockStrings.description%", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "string" + } + } } } } - }, - "default": [ - { - "types": [ - "cpp" - ], - "patterns": [ - [ - "R\"(", - ")\"" - ] - ] - }, - { - "types": [ - "lua" - ], - "patterns": [ - [ - "[[", - "]]" - ] - ] - }, - { - "types": [ - ".js", - ".jsx", - ".ts", - ".tsx" - ], - "patterns": [ - [ - "`", - "`" - ] - ] - } - ] + } } } } @@ -250,20 +259,20 @@ "test": "node ./out/test/runTest.js" }, "devDependencies": { - "@types/glob": "^7.1.1", + "@types/glob": "^7.1.2", "@types/graceful-fs": "^4.1.3", "@types/minimatch": "^3.0.3", - "@types/mocha": "^5.2.7", - "@types/node": "^12.11.7", - "@types/vscode": "^1.40.0", - "glob": "^7.1.5", - "mocha": "^6.2.2", - "tslint": "^5.20.0", - "typescript": "^3.6.4", - "vscode-test": "^1.2.2" + "@types/mocha": "^7.0.2", + "@types/node": "^14.0.14", + "@types/vscode": "^1.46.0", + "glob": "^7.1.6", + "mocha": "^8.0.1", + "tslint": "^6.1.2", + "typescript": "^3.9.6", + "vscode-test": "^1.4.0" }, "dependencies": { - "jsonc-parser": "^2.2.0", + "jsonc-parser": "^2.3.0", "minimatch": "^3.0.4" } } diff --git a/package.nls.ja.json b/package.nls.ja.json index 39bb5ad..a0f714a 100644 --- a/package.nls.ja.json +++ b/package.nls.ja.json @@ -3,7 +3,8 @@ "commands.countInDirectory.title": "ディレクトリ内のコード行を数える", "commands.countInWorkspace.title": "ワークスペース内のコード行を数える", "commands.outputAvailableLanguages.title": "利用可能な言語を確認する", - "configuration.showInStatusBar.description": "現在のファイルのカウント結果をリアルタイムでステータスバーに表示する.", + "commands.saveLanguageConfigurations.title": "収集した言語設定を保存する", + "configuration.useGitignore.description": "対象ファイルを除外するために '.gitignore' を使う.", "configuration.useFilesExclude.description": "対象ファイルを除外するために 'files.exclude' 設定を使う.", "configuration.printNumberWithCommas.description": "数値をカンマ区切りで出力する (CSVを除く).", @@ -17,7 +18,12 @@ "configuration.outputAsMarkdown.description": "結果をMarkdown形式で出力する.", "configuration.outputMarkdownSeparately.description": "Markdown結果を概要と詳細で分けて出力する.", "configuration.outputPreviewType.description": "カウント後にプレビューする出力ファイルの種類.", - "configuration.blockComment.description": "ブロックコメント(ヒアドキュメント)の先頭と末尾を示すパターンを定義する.\n複数行にまたがるような文字列を判別するために使用する.この内部に現れたコメント行はコード行とみなされる.\n -types: 言語の種類. languageId(例 cpp, csharp, javascript...), エイリアス名(例 C++, C#, JavaScript), 拡張子(eg .cpp, .cs, .js) のいずれかで指定する.\n - patterns: コメント範囲を示すパターン.", - "configuration.blockComment.types.description": "言語の種類.\n languageId(例 cpp, csharp, javascript...), エイリアス名(例 C++, C#, JavaScript), 拡張子(eg .cpp, .cs, .js) のいずれかで指定する.", - "configuration.blockComment.patterns.description": "コメント範囲を示すパターン." + "configuration.saveLocation.description": "集めた言語設定を保存する場所を指定する.", + "configuration.languages.description": "保存された言語設定.", + "configuration.languages.aliases.description": "言語の別名.", + "configuration.languages.filenames.description": "言語に関連付けられたファイル名.", + "configuration.languages.extensions.description": "言語に関連付けられたファイル拡張子.", + "configuration.languages.lineComments.description": "行コメントを開始する文字列.", + "configuration.languages.blockComments.description": "ブロックコメントの開始と終了を示す文字列.", + "configuration.languages.blockStrings.description": "複数行文字列(ヒアドキュメント)の先頭と末尾を示す文字列." } \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index 9a15675..80b2679 100644 --- a/package.nls.json +++ b/package.nls.json @@ -3,7 +3,8 @@ "commands.countInDirectory.title": "Count lines in directory", "commands.countInWorkspace.title": "Count lines in workspace", "commands.outputAvailableLanguages.title": "Check available languages", - "configuration.showInStatusBar.description": "Whether to show the count result of the current file on the status bar in real time.", + "commands.saveLanguageConfigurations.title": "Save the collected language configurations", + "configuration.useGitignore.description": "Whether to use '.gitignore' files for excluding files.", "configuration.useFilesExclude.description": "Whether to use setting 'files.exclude' for excluding files.", "configuration.printNumberWithCommas.description": "Whether to print a number with commas as thousands separators.(except for CSV)", @@ -17,7 +18,12 @@ "configuration.outputAsMarkdown.description": "Whether to output the result as a Markdown file.", "configuration.outputMarkdownSeparately.description": "Whether to output summary and details separately.", "configuration.outputPreviewType.description": "Type of output file to preview after counting.", - "configuration.blockComment.description": "Define patterns indicating the beginning and end of the block document(here document).\nIt is used to distinguish between strings that span multiple lines, and the comment lines displayed in it are considered code lines.\n - types: Language types. Allows you to specify languageId(eg cpp, csharp, javascript...), aliases(eg C++, C#, JavaScript), and extensions(eg .cpp, .cs, .js).\n - patterns: patterns indicating the range of comments.", - "configuration.blockComment.types.description": "Language types. \nAllows you to specify languageId(eg cpp, csharp, javascript...), aliases(eg C++, C#, JavaScript), and extensions(eg .cpp, .cs, .js).", - "configuration.blockComment.patterns.description": "patterns indicating the range of comments." + "configuration.saveLocation.description": "Specify where to store the collected language configurations.", + "configuration.languages.description": "Saved Language Configurations.", + "configuration.languages.aliases.description": "Name aliases for the language.", + "configuration.languages.filenames.description": "Filenames associated to the language.", + "configuration.languages.extensions.description": "File extensions associated to the language.", + "configuration.languages.lineComments.description": "The character sequence that starts a line comment.", + "configuration.languages.blockComments.description": "The character sequence indicating the beginning and end of the block comment.", + "configuration.languages.blockStrings.description": "The character sequence indicating the beginning and end of the block document(here document)." } \ No newline at end of file diff --git a/src/LineCounter.ts b/src/LineCounter.ts index b4e6c50..e061730 100644 --- a/src/LineCounter.ts +++ b/src/LineCounter.ts @@ -2,42 +2,17 @@ export default class LineCounter { - private id: string; - private aliases: string[] = []; - private lineComment: string[] = []; - public blockComment: {begin:string, end:string}[] = []; - public blockString: {begin:string, end:string}[] = []; + public readonly name: string; + private lineComments: string[]; + private blockComments: [string, string][]; + private blockStrings: [string, string][]; - get languageId(): string { - return this.aliases.length > 0 ? this.aliases[0] : this.id; + constructor(name:string, lineComments:string[], blockComments:[string,string][], blockStrings:[string,string][]) { + this.name = name; + this.lineComments = lineComments; + this.blockComments = blockComments; + this.blockStrings = blockStrings; } - - constructor(id:string) { - this.id = id; - } - public addAlias(aliases: string[]) { - this.aliases.push(...aliases); - } - public addLineCommentRule(...tokens: string[]) { - this.lineComment.push(...tokens); - } - public addBlockCommentRule(...tokenPairs: {begin:string, end:string}[]) { - this.blockComment.push(...tokenPairs); - } - public addBlockStringRule(...tokenPairs: {begin:string, end:string}[]) { - this.blockString.push(...tokenPairs); - } - public addCommentRule(rule: any) { - if (rule) { - if (typeof(rule.lineComment) === 'string' && rule.lineComment.length > 0) { - this.lineComment.push(rule.lineComment as string); - } - if (rule.blockComment && (rule.blockComment.length >= 2)) { - this.addBlockCommentRule({begin: rule.blockComment[0], end: rule.blockComment[1]}); - } - } - } - public count(text: string): {code:number, comment:number, blank:number} { enum LineType {Code, Comment, Blank} @@ -72,28 +47,28 @@ export default class LineCounter } } else { // now is line comment. - if (this.lineComment.some(lc => line.startsWith(lc))) { + if (this.lineComments.some(lc => line.startsWith(lc))) { type = LineType.Comment; break; } { let index = -1; - const range = this.blockComment.find(bc => { index = line.indexOf(bc.begin, i); return index >= 0; }); + const range = this.blockComments.find(bc => { index = line.indexOf(bc[0], i); return index >= 0; }); if (range !== undefined) { // start block comment type = index === 0 ? LineType.Comment : LineType.Code; - blockCommentEnd = range.end; - i = index + range.begin.length; + blockCommentEnd = range[1]; + i = index + range[0].length; continue; } } type = LineType.Code; { let index = -1; - const rabge = this.blockString.find(bc => { index = line.indexOf(bc.begin, i); return index >= 0; }); - if (rabge !== undefined) { - blockStringEnd = rabge.end; - i = index + rabge.begin.length; + const range = this.blockStrings.find(bc => { index = line.indexOf(bc[0], i); return index >= 0; }); + if (range !== undefined) { + blockStringEnd = range[1]; + i = index + range[0].length; continue; } } diff --git a/src/extension.ts b/src/extension.ts index 7c2f1d9..a70f7a9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,12 +3,12 @@ // Import the module and reference it with the alias vscode in your code below import * as vscode from 'vscode'; import * as path from 'path'; -// import * as fs from 'graceful-fs'; import LineCounter from './LineCounter'; import Gitignore from './Gitignore'; import * as JSONC from 'jsonc-parser'; import * as minimatch from 'minimatch'; import { TextDecoder, TextEncoder } from 'util'; +// import { debug } from 'console'; const EXTENSION_ID = 'uctakeoff.vscode-counter'; const EXTENSION_NAME = 'VSCodeCounter'; @@ -23,28 +23,21 @@ const toStringWithCommas = (obj: any) => { return obj.toString(); } }; -const log = (message: string) => console.log(`[${EXTENSION_NAME}] ${new Date().toISOString()} ${message}`); +const log = (message: string, ...items:any[]) => console.log(`[${EXTENSION_NAME}] ${new Date().toISOString()} ${message}`, ...items); +const showError = (message: string, ...items:any[]) => vscode.window.showErrorMessage(`[${EXTENSION_NAME}] ${message}`, ...items); // this method is called when your extension is activated // your extension is activated the very first time the command is executed export function activate(context: vscode.ExtensionContext) { - let version = "-"; - const ext = vscode.extensions.getExtension(EXTENSION_ID); - if (ext !== undefined && (typeof ext.packageJSON.version === 'string')) { - version = ext.packageJSON.version; - } - // Use the console to output diagnostic information (console.log) and errors (console.error) - // This line of code will only be executed once when your extension is activated + const version = vscode.extensions.getExtension(EXTENSION_ID)?.packageJSON?.version; log(`${EXTENSION_ID} ver.${version} now active! : ${context.extensionPath}`); - // The command has been defined in the package.json file - // Now provide the implementation of the command with registerCommand - // The commandId parameter must match the command field in package.json const codeCountController = new CodeCounterController(); context.subscriptions.push( codeCountController, vscode.commands.registerCommand('extension.vscode-counter.countInWorkspace', () => codeCountController.countInWorkspace()), vscode.commands.registerCommand('extension.vscode-counter.countInDirectory', (targetDir: vscode.Uri|undefined) => codeCountController.countInDirectory(targetDir)), vscode.commands.registerCommand('extension.vscode-counter.countInFile', () => codeCountController.toggleVisible()), + vscode.commands.registerCommand('extension.vscode-counter.saveLanguageConfigurations', () => codeCountController.saveLanguageConfigurations()), vscode.commands.registerCommand('extension.vscode-counter.outputAvailableLanguages', () => codeCountController.outputAvailableLanguages()) ); } @@ -52,15 +45,23 @@ export function activate(context: vscode.ExtensionContext) { export function deactivate() { } -const workspaceFolders = (): readonly vscode.WorkspaceFolder[] => { - const folders = vscode.workspace.workspaceFolders; - return !folders ? [] : folders; -}; +async function currentWorkspaceFolder() { + const folders = vscode.workspace.workspaceFolders ?? []; + if (folders.length <= 0) { + return undefined; + } else if (folders.length === 1) { + return folders[0]; + } else { + return await vscode.window.showWorkspaceFolderPick(); + } +} class CodeCounterController { - private configuration: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(CONFIGURATION_SECTION); - private codeCounter_: CodeCounter|null = null; + private codeCounter_: LineCounterTable|null = null; + private statusBarItem: vscode.StatusBarItem|null = null; + private outputChannel: vscode.OutputChannel|null = null; private disposable: vscode.Disposable; + constructor() { // subscribe to selection change and editor activation events let subscriptions: vscode.Disposable[] = []; @@ -70,105 +71,149 @@ class CodeCounterController { vscode.workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, subscriptions); // create a combined disposable from both event subscriptions this.disposable = vscode.Disposable.from(...subscriptions); - if (this.isVisible) { - this.codeCounter.countCurrentFile(); - } } dispose() { + this.statusBarItem?.dispose(); + this.statusBarItem = null; + this.outputChannel?.dispose(); + this.outputChannel = null; this.disposable.dispose(); - this.disposeCodeCounter(); + this.codeCounter_ = null; } - private get codeCounter() { - if (this.codeCounter_ === null) { - this.codeCounter_ = new CodeCounter(this.configuration); + private async getCodeCounter() { + if (this.codeCounter_) { + return this.codeCounter_ } + const langs = await loadLanguageConfigurations(); + log(`load Language Settings = ${langs.size}`); + await collectLanguageConfigurations(langs); + log(`collect Language Settings = ${langs.size}`); + const filesConf = vscode.workspace.getConfiguration("files", null); + this.codeCounter_ = new LineCounterTable(langs, Object.entries(filesConf.get<{[key:string]:string}>('associations', {}))); + //this.saveLanguageConfigurations(langs); return this.codeCounter_; } - private disposeCodeCounter() { - if (this.codeCounter_ !== null) { - this.codeCounter_.dispose(); - this.codeCounter_ = null; - } - } - private get isVisible() { - return this.configuration.get('showInStatusBar', false); - } - public toggleVisible() { - this.configuration.update('showInStatusBar', !this.isVisible); + public saveLanguageConfigurations() { + this.getCodeCounter() + .then(c => saveLanguageConfigurations(c.entries())) + .catch(reason => showError(`saveLanguageConfigurations() failed.`, reason)); } + public outputAvailableLanguages() { - this.codeCounter.outputAvailableLanguages(); + this.getCodeCounter().then(c => { + c.entries().forEach((lang, id) => { + this.toOutputChannel(`${id} : aliases[${lang.aliases}], extensions[${lang.extensions}], filenames:[${lang.filenames}]`); + }); + this.toOutputChannel(`VS Code Counter : available all ${c.entries().size} languages.`); + }) + .catch(reason => showError(`outputAvailableLanguages() failed.`, reason)); } - public countInDirectory(targetDir: vscode.Uri|undefined) { + + public async countInDirectory(targetDir: vscode.Uri|undefined) { try { - const folders = workspaceFolders(); - if (folders.length <= 0) { - vscode.window.showErrorMessage(`[${EXTENSION_NAME}] No open workspace`); - } else if (targetDir !== undefined) { - this.codeCounter.countLinesInDirectory(targetDir, folders[0].uri); + const folder = await currentWorkspaceFolder(); + if (!folder) { + showError(`No open workspace`); + } else if (targetDir) { + this.countLinesInDirectory(targetDir, folder.uri); } else { const option = { - value : folders[0].uri.toString(true), + value : folder.uri.toString(true), placeHolder: "Input Directory Path", prompt: "Input Directory Path. " }; - vscode.window.showInputBox(option).then(uri => { - if (uri !== undefined) { - this.codeCounter.countLinesInDirectory(vscode.Uri.parse(uri), folders[0].uri); - } - }); + const uri = await vscode.window.showInputBox(option); + if (uri) { + this.countLinesInDirectory(vscode.Uri.parse(uri), folder.uri); + } } } catch (e) { - vscode.window.showErrorMessage(`[${EXTENSION_NAME}] countInDirectory() failed.`, e.message); + showError(`countInDirectory() failed.`, e.message); } } - public countInWorkspace() { + public async countInWorkspace() { try { - const folders = workspaceFolders(); - if (folders.length <= 0) { - vscode.window.showErrorMessage(`[${EXTENSION_NAME}] No open workspace`); - } else if (folders.length === 1) { - this.codeCounter.countLinesInDirectory(folders[0].uri, folders[0].uri); + const folder = await currentWorkspaceFolder(); + if (folder) { + this.countLinesInDirectory(folder.uri, folder.uri); } else { - vscode.window.showWorkspaceFolderPick().then((folder) => { - if (folder) { - this.codeCounter.countLinesInDirectory(folder.uri, folder.uri); - } - }); + showError(`No folder are open.`); } } catch (e) { - vscode.window.showErrorMessage(`[${EXTENSION_NAME}] countInWorkspace() failed.`, e.message); + showError(`countInWorkspace() failed.`, e.message); } } + private countLinesInDirectory(targetUri: vscode.Uri, workspaceDir: vscode.Uri) { + const conf = vscode.workspace.getConfiguration(CONFIGURATION_SECTION); + const outputDir = buildUri(workspaceDir, conf.get('outputDirectory', '.VSCodeCounter')); + this.getCodeCounter() + .then(c => countLinesInDirectory(c, targetUri, outputDir, conf, this.toOutputChannel)) + .then(results => outputResults(targetUri, results, outputDir, conf)) + .catch(reason => showError(`countLinesInDirectory() failed.`, reason)); + } + private onDidChangeWorkspaceFolders(e: vscode.WorkspaceFoldersChangeEvent) { log(`onDidChangeWorkspaceFolders()`); - e.added.forEach((f) => log(` added [${f.index}] ${f.name} : ${f.uri}`)); - e.removed.forEach((f) => log(` removed [${f.index}] ${f.name} : ${f.uri}`)); - workspaceFolders().forEach((f) => log(` [${f.index}] ${f.name} : ${f.uri}`)); + // e.added.forEach((f) => log(` added [${f.index}] ${f.name} : ${f.uri}`)); + // e.removed.forEach((f) => log(` removed [${f.index}] ${f.name} : ${f.uri}`)); + // vscode.workspace.workspaceFolders?.forEach((f) => log(` [${f.index}] ${f.name} : ${f.uri}`)); } private onDidChangeActiveTextEditor(e: vscode.TextEditor|undefined) { - if (this.codeCounter_ !== null) { + if (this.codeCounter_) { log(`onDidChangeActiveTextEditor(${!e ? 'undefined' : e.document.uri})`); - this.codeCounter.countFile((e !== undefined) ? e.document : undefined); + this.countFile(e?.document); } } private onDidChangeTextDocument(e: vscode.TextDocumentChangeEvent) { - if (this.codeCounter_ !== null) { + if (this.codeCounter_) { log(`onDidChangeTextDocument(${e.document.uri})`); - this.codeCounter.countFile(e.document); + this.countFile(e.document); } } private onDidChangeConfiguration() { - const newConf = vscode.workspace.getConfiguration(CONFIGURATION_SECTION); - if (JSON.stringify(this.configuration) !== JSON.stringify(newConf)) { - log(`onDidChangeConfiguration()`); - this.configuration = newConf; - this.disposeCodeCounter(); - if (this.isVisible) { - this.codeCounter.countCurrentFile(); - } + log(`onDidChangeConfiguration()`); + this.codeCounter_ = null; + this.countFile(vscode.window.activeTextEditor?.document); + } + + public toggleVisible() { + if (!this.statusBarItem) { + this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + this.countFile(vscode.window.activeTextEditor?.document); + } else { + this.statusBarItem.dispose(); + this.statusBarItem = null; + } + } + private showStatusBar(text: string) { + if (this.statusBarItem) { + this.statusBarItem.show(); + this.statusBarItem.text = text; + } + } + private countFile(doc: vscode.TextDocument|undefined) { + if (!doc) { + this.showStatusBar(`${EXTENSION_NAME}:Unsupported`); + } else { + this.getCodeCounter().then(c =>{ + const lineCounter = c.getById(doc.languageId) || c.getByUri(doc.uri); + if (lineCounter) { + const result = lineCounter?.count(doc.getText()); + this.showStatusBar(`Code:${result.code} Comment:${result.comment} Blank:${result.blank}`); + } else { + this.showStatusBar(`${EXTENSION_NAME}:Unsupported`); + } + }); } } + private toOutputChannel(text: string) { + if (!this.outputChannel) { + this.outputChannel = vscode.window.createOutputChannel(EXTENSION_NAME); + } + this.outputChannel.show(); + this.outputChannel.appendLine(text); + } + } const encodingTable = new Map([ ['big5hkscs', 'big5-hkscs'], @@ -224,7 +269,7 @@ const buildUri = (uri: vscode.Uri, filename: string) => uri.with({path: `${uri.p const dirUri = (uri: vscode.Uri) => uri.with({path: path.dirname(uri.path)}); function readFileAll(fileUris: vscode.Uri[]) : Promise<{uri:vscode.Uri, data:Uint8Array|null, error?:any}[]> { - const ret = new Array<{uri:vscode.Uri, data:Uint8Array|null, error?:any}>(); + const ret: {uri:vscode.Uri, data:Uint8Array|null, error?:any}[] = []; return new Promise((resolve: (values: {uri:vscode.Uri, data:Uint8Array|null, error?:any}[])=> void, reject: (reason: any) => void) => { if (fileUris.length > 0) { fileUris.forEach(fileUri => { @@ -248,272 +293,243 @@ function readFileAll(fileUris: vscode.Uri[]) : Promise<{uri:vscode.Uri, data:Uin } }); } -class CodeCounter { - private outputChannel: vscode.OutputChannel|null = null; - private statusBarItem: vscode.StatusBarItem|null = null; - private configuration: vscode.WorkspaceConfiguration; - private langExtensions: VscodeLangExtension[]; - private lineCounterTable: LineCounterTable; - - constructor(configuration: vscode.WorkspaceConfiguration) { - log(`build CodeCounter start`); - this.configuration = configuration; - const confFiles = vscode.workspace.getConfiguration("files", null); - this.langExtensions = loadLanguageExtensions(); - this.lineCounterTable = new LineCounterTable(this.langExtensions, this.configuration, [...Object.entries(confFiles.get('associations', {}))]); - if (this.getConf('showInStatusBar', false)) { - this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - } - log(`create CodeCounter end`); - } - dispose() { - if (this.statusBarItem !== null) { - this.statusBarItem.dispose(); - } - if (this.outputChannel !== null) { - this.outputChannel.dispose(); - } - log(`dispose CodeCounter`); - } - private getConf(section: string, defaultValue: T): T { - return this.configuration.get(section, defaultValue); - } - private toOutputChannel(text: string) { - if (this.outputChannel === null) { - this.outputChannel = vscode.window.createOutputChannel(EXTENSION_NAME); - } - this.outputChannel.show(); - this.outputChannel.appendLine(text); - } - public outputAvailableLanguages() { - this.langExtensions.forEach((lang) => { - this.toOutputChannel(`${lang.id} : aliases[${lang.aliases}], extensions[${lang.extensions}], filenames:[${lang.filenames}]`); - }); - this.toOutputChannel(`VS Code Counter : available all ${this.langExtensions.length} languages.`); - } - public countLinesInDirectory(targetUri: vscode.Uri, outputDirUri: vscode.Uri) { - // const outputDir = path.resolve(outputDirUri.fsPath, this.getConf('outputDirectory', '.VSCodeCounter')); - const outputDir = buildUri(outputDirUri, this.getConf('outputDirectory', '.VSCodeCounter')); - log(`countLinesInDirectory : ${targetUri}, output dir: ${outputDir}`); - const confFiles = vscode.workspace.getConfiguration("files", null); - const includes = this.getConf>('include', ['**/*']); - const excludes = this.getConf>('exclude', []); - if (this.getConf('useFilesExclude', true)) { - excludes.push(...Object.keys(confFiles.get('exclude', {}))); - } - const encoding = confFiles.get('encoding', 'utf8'); - const decoder = new TextDecoder(encodingTable.get(encoding) || encoding); - const decoderU8 = new TextDecoder('utf8'); +function countLinesInDirectory(lineCounterTable: LineCounterTable, targetUri: vscode.Uri, outputDir: vscode.Uri, configuration: vscode.WorkspaceConfiguration, consoleOut:(text:string)=>void) { + log(`countLinesInDirectory : ${targetUri}, output dir: ${outputDir.fsPath}`); + const confFiles = vscode.workspace.getConfiguration("files", null); + const includes = configuration.get('include', ['**/*']); + const excludes = configuration.get('exclude', []); + if (configuration.get('useFilesExclude', true)) { + excludes.push(...Object.keys(confFiles.get('exclude', {}))); + } + const encoding = confFiles.get('encoding', 'utf8'); + const decoder = new TextDecoder(encodingTable.get(encoding) || encoding); + const decoderU8 = new TextDecoder('utf8'); - excludes.push(vscode.workspace.asRelativePath(outputDir)); - log(`includes : "${includes.join('", "')}"`); - log(`excludes : "${excludes.join('", "')}"`); + excludes.push(vscode.workspace.asRelativePath(outputDir)); + log(`includes : "${includes.join('", "')}"`); + log(`excludes : "${excludes.join('", "')}"`); - new Promise((resolve: (p: vscode.Uri[])=> void, reject: (reason: any) => void) => { - vscode.workspace.findFiles(`{${includes.join(',')}}`, `{${excludes.join(',')}}`).then((files: vscode.Uri[]) => { - const fileUris = files.filter(uri => uri.path.startsWith(targetUri.path)); - if (this.getConf('useGitignore', true)) { - log(`target : ${fileUris.length} files -> use .gitignore`); - vscode.workspace.findFiles('**/.gitignore', '').then((gitignoreFiles: vscode.Uri[]) => { - gitignoreFiles.forEach(f => log(`use gitignore : ${f}`)); - readFileAll(gitignoreFiles.sort()).then((values) => { - const gitignores = new Gitignore('').merge(...values.map(p => new Gitignore(decoderU8.decode(p.data), dirUri(p.uri).fsPath))); - resolve(fileUris.filter(p => gitignores.excludes(p.fsPath))); - }, - reject - ); - // const t = .map(p => vscode.workspace.fs.readFile(p)); - // const gitignores = new Gitignore('').merge(...gitignoreFiles.map(uri => uri.fsPath).sort().map(p => new Gitignore(fs.readFileSync(p, 'utf8'), path.dirname(p)))); - // resolve(fileUris.filter(p => gitignores.excludes(p.fsPath))); + return new Promise((resolve: (p: vscode.Uri[])=> void, reject: (reason: any) => void) => { + vscode.workspace.findFiles(`{${includes.join(',')}}`, `{${excludes.join(',')}}`).then((files: vscode.Uri[]) => { + const fileUris = files.filter(uri => uri.path.startsWith(targetUri.path)); + if (configuration.get('useGitignore', true)) { + log(`target : ${fileUris.length} files -> use .gitignore`); + vscode.workspace.findFiles('**/.gitignore', '').then((gitignoreFiles: vscode.Uri[]) => { + gitignoreFiles.forEach(f => log(`use gitignore : ${f}`)); + readFileAll(gitignoreFiles.sort()).then((values) => { + const gitignores = new Gitignore('').merge(...values.map(p => new Gitignore(decoderU8.decode(p.data), dirUri(p.uri).fsPath))); + resolve(fileUris.filter(p => gitignores.excludes(p.fsPath))); }, reject ); - } else { - resolve(fileUris); - } - }); - }).then((fileUris: vscode.Uri[]) => { - log(`target : ${fileUris.length} files`); - return new Promise((resolve: (value: Result[])=> void, reject: (reason: string) => void) => { - const results: Result[] = []; - if (fileUris.length <= 0) { - resolve(results); - } - const ignoreUnsupportedFile = this.getConf('ignoreUnsupportedFile', true); - let fileCount = 0; - fileUris.forEach(fileUri => { - const lineCounter = this.lineCounterTable.getByUri(fileUri); - if (lineCounter !== undefined) { -/* - fs.readFile(fileUri.fsPath, encoding, (err, data) => { - ++fileCount; - if (err) { - this.toOutputChannel(`"${fileUri}" Read Error : ${err.message}.`); - results.push(new Result(fileUri, '(Read Error)')); - } else { - results.push(new Result(fileUri, lineCounter.languageId, lineCounter.count(data))); - } - if (fileCount === fileUris.length) { - resolve(results); - } - }); -*/ - vscode.workspace.fs.readFile(fileUri).then(data => { - ++fileCount; - try { - results.push(new Result(fileUri, lineCounter.languageId, lineCounter.count(decoder.decode(data)))); - } catch (e) { - this.toOutputChannel(`"${fileUri}" Read Error : ${e.message}.`); - results.push(new Result(fileUri, '(Read Error)')); - } - if (fileCount === fileUris.length) { - resolve(results); - } - }, - (reason: any) => { - this.toOutputChannel(`"${fileUri}" Read Error : ${reason}.`); + }, + reject + ); + } else { + resolve(fileUris); + } + }); + }).then((fileUris: vscode.Uri[]) => { + log(`target : ${fileUris.length} files`); + return new Promise((resolve: (value: Result[])=> void, reject: (reason: string) => void) => { + const results: Result[] = []; + if (fileUris.length <= 0) { + resolve(results); + } + const ignoreUnsupportedFile = configuration.get('ignoreUnsupportedFile', true); + let fileCount = 0; + fileUris.forEach(fileUri => { + const lineCounter = lineCounterTable.getByUri(fileUri); + if (lineCounter) { + vscode.workspace.fs.readFile(fileUri).then(data => { + ++fileCount; + try { + results.push(new Result(fileUri, lineCounter.name, lineCounter.count(decoder.decode(data)))); + } catch (e) { + consoleOut(`"${fileUri}" Read Error : ${e.message}.`); results.push(new Result(fileUri, '(Read Error)')); - }); - } else { - if (!ignoreUnsupportedFile) { - results.push(new Result(fileUri, '(Unsupported)')); } - ++fileCount; if (fileCount === fileUris.length) { resolve(results); } + }, + (reason: any) => { + consoleOut(`"${fileUri}" Read Error : ${reason}.`); + results.push(new Result(fileUri, '(Read Error)')); + }); + } else { + if (!ignoreUnsupportedFile) { + results.push(new Result(fileUri, '(Unsupported)')); } - }); + ++fileCount; + if (fileCount === fileUris.length) { + resolve(results); + } + } }); - }).then((results: Result[]) => { - outputResults(targetUri, results, outputDir, this.configuration); - }).catch((reason: string) => { - vscode.window.showErrorMessage(`[${EXTENSION_NAME}] countLinesInDirectory() failed.`, reason); }); - } - private countFile_(doc: vscode.TextDocument|undefined) { - if (doc !== undefined) { - const lineCounter = this.lineCounterTable.getById(doc.languageId) || this.lineCounterTable.getByUri(doc.uri); - log(`${doc.uri}: ${JSON.stringify(lineCounter)}`); - if (lineCounter !== undefined) { - const result = lineCounter.count(doc.getText()); - // return `Code:${result.code} Comment:${result.comment} Blank:${result.blank} Total:${result.code+result.comment+result.blank}`; - return `Code:${result.code} Comment:${result.comment} Blank:${result.blank}`; - } + }); +} + +type VscodeLanguage = { + id: string + aliases?: string[] + filenames?: string[] + extensions?: string[] + configuration?: string +}; +type LanguageConf = { + aliases: string[] + filenames: string[] + extensions: string[] + lineComments: string[] + blockComments: [string,string][] + blockStrings: [string,string][] +} +function pushUnique(array: T[], ...values: T[]) { + values.forEach(value => { + if (array.indexOf(value) < 0) { + array.push(value); } - return `${EXTENSION_NAME}:Unsupported`; - } - public countFile(doc: vscode.TextDocument|undefined) { - if (this.statusBarItem !== null) { - this.statusBarItem.show(); - this.statusBarItem.text = this.countFile_(doc); + }); +} +const append = (langs: Map, l:VscodeLanguage) => { + const langExt = getOrSet(langs, l.id, ():LanguageConf => { + return { + aliases:[], + filenames:[], + extensions:[], + lineComments:[], + blockComments:[], + blockStrings:[] } - } - public countCurrentFile() { - // Get the current text editor - const editor = vscode.window.activeTextEditor; - if (editor !== undefined) { - this.countFile(editor.document); + }); + // l.aliases?.filter(v => langExt.aliases.indexOf(v) < 0).forEach(v => langExt.aliases.push(v)); + // l.filenames?.filter(v => langExt.filenames.indexOf(v) < 0).forEach(v => langExt.filenames.push(v)); + // l.extensions?.filter(v => langExt.extensions.indexOf(v) < 0).forEach(v => langExt.extensions.push(v)); + pushUnique(langExt.aliases, ...(l.aliases??[])); + pushUnique(langExt.filenames, ...(l.filenames??[])); + pushUnique(langExt.extensions, ...(l.extensions??[])); + return langExt; +} + +function collectLanguageConfigurations(langs: Map) : Promise> { + return new Promise((resolve: (values: Map)=> void, reject: (reason: any) => void) => { + if (vscode.extensions.all.length <= 0) { + resolve(langs); } else { - this.countFile(undefined); + let finishedCount = 0; + let totalCount = 0; + const decoderU8 = new TextDecoder('utf8'); + vscode.extensions.all.forEach(ex => { + const languages = ex.packageJSON.contributes?.languages as VscodeLanguage[] ?? undefined; + if (languages) { + totalCount += languages.length + languages.forEach(l => { + const langExt = append(langs, l); + if (l.configuration) { + const confUrl = vscode.Uri.file(path.join(ex.extensionPath, l.configuration)); + vscode.workspace.fs.readFile(confUrl).then(data => { + // log(`${confUrl} ${data.length}B :${l.id}`); + const langConf = JSONC.parse(decoderU8.decode(data)) as vscode.LanguageConfiguration; + if (langConf.comments) { + if (langConf.comments.lineComment) { + pushUnique(langExt.lineComments, langConf.comments.lineComment); + } + if (langConf.comments.blockComment && langConf.comments.blockComment.length >= 2) { + pushUnique(langExt.blockComments, langConf.comments.blockComment); + } + } + if (++finishedCount >= totalCount) { + resolve(langs); + } + }, + (reason:any) => { + log(`${confUrl} : error ${reason}`); + if (++finishedCount >= totalCount) { + resolve(langs); + } + }); + + } else { + if (++finishedCount >= totalCount) { + resolve(langs); + } + } + }); + } + }); } + }); +} +function saveLanguageConfigurations_(langs: {[key:string]:LanguageConf}) { + const conf = vscode.workspace.getConfiguration(CONFIGURATION_SECTION); + const saveLocation = conf.get('saveLocation', 'global settings'); + if (saveLocation === "global settings") { + conf.update('languages', langs, vscode.ConfigurationTarget.Global); + } else if (saveLocation === "workspace settings") { + conf.update('languages', langs, vscode.ConfigurationTarget.Workspace); + } else if (saveLocation === "output directory") { + currentWorkspaceFolder().then(async (folder) => { + if (!folder) return; + const outputDirUri = buildUri(folder.uri, conf.get('outputDirectory', '.VSCodeCounter')); + const uri = buildUri(outputDirUri, 'languages.json'); + await makeDirectories(outputDirUri); + writeTextFile(uri, JSON.stringify(langs)); + }); } } - -class VscodeLangExtension { - extensionPath: string; - id:string; - aliases:string[]; - filenames:string[]; - extensions:string[]; - configuration:vscode.Uri|undefined; - - constructor(extensionPath:string, language:{id:string, aliases:string[]|undefined, filenames:string[]|undefined, extensions:string[]|undefined, configuration:string|undefined}) { - this.extensionPath = extensionPath; - this.id = language.id; - this.aliases = language.aliases !== undefined ? language.aliases : []; - this.filenames = language.filenames !== undefined ? language.filenames : []; - this.extensions = language.extensions !== undefined ? language.extensions : []; - this.configuration = language.configuration !== undefined ? vscode.Uri.file(path.join(this.extensionPath, language.configuration)) : undefined; +function saveLanguageConfigurations(langs: Map) { + saveLanguageConfigurations_(mapToObject(langs)); +} +async function loadLanguageConfigurations_() { + const conf = vscode.workspace.getConfiguration(CONFIGURATION_SECTION); + const saveLocation = conf.get('saveLocation', 'global settings'); + if (saveLocation === "global settings") { + return conf.get<{[key:string]:LanguageConf}>('languages', {}); + } else if (saveLocation === "workspace settings") { + return conf.get<{[key:string]:LanguageConf}>('languages', {}); + } else if (saveLocation === "output directory") { + const workFolder = await currentWorkspaceFolder(); + if (!workFolder) return {}; + const outputDirUri = buildUri(workFolder.uri, conf.get('outputDirectory', '.VSCodeCounter')); + const uri = buildUri(outputDirUri, 'languages.json'); + const data = await vscode.workspace.fs.readFile(uri); + const decoderU8 = new TextDecoder('utf8'); + return JSONC.parse(decoderU8.decode(data)) as {[key:string]:LanguageConf}; + } else { + return {}; } } -function loadLanguageExtensions() : VscodeLangExtension[] { - const ret : VscodeLangExtension[] = []; - vscode.extensions.all.forEach(ex => { - const contributes = ex.packageJSON.contributes; - if (contributes !== undefined) { - const languages = contributes.languages; - if (languages !== undefined) { - (languages as Array).forEach(l => ret.push(new VscodeLangExtension(ex.extensionPath, l))); - } - } - }); - return ret; +async function loadLanguageConfigurations() { + return objectToMap(await loadLanguageConfigurations_()); } - class LineCounterTable { + private langExtensions: Map; private langIdTable: Map; private aliasTable: Map; private fileextRules: Map; private filenameRules: Map; private associations: [string, string][]; - constructor(langExtensions: VscodeLangExtension[], conf: vscode.WorkspaceConfiguration, associations: [string, string][]) { + constructor(langExtensions: Map, associations: [string, string][]) { + this.langExtensions = langExtensions; this.langIdTable = new Map(); this.aliasTable = new Map(); this.fileextRules = new Map(); this.filenameRules = new Map(); this.associations = associations; log(`associations : ${this.associations.length}\n[${this.associations.join("],[")}]`); - - const confJsonTable = new Map(); - const decoderU8 = new TextDecoder('utf8'); - - langExtensions.forEach(lang => { - // log(`${lang.id} : aliases[${lang.aliases}], extensions[${lang.extensions}], filenames:[${lang.filenames}], configuration:[${lang.configuration}]`); - const lineCounter = getOrSetFirst(this.langIdTable, lang.id, () => new LineCounter(lang.id)); - lineCounter.addAlias(lang.aliases); - lang.aliases.forEach((alias:string) => { - this.aliasTable.set(alias, lineCounter); - }); - const confpath = lang.configuration; - if (confpath !== undefined) { - vscode.workspace.fs.readFile(confpath).then(data => { - // log(`"${confpath}" : ${data.length}B`); - const v = getOrSetFirst(confJsonTable, confpath.toString(), () => JSONC.parse(decoderU8.decode(data))); - // log(` ${JSON.stringify(v)}`); - lineCounter.addCommentRule(v.comments); - }); - } - lang.extensions.forEach(ex => this.fileextRules.set(ex.startsWith('.') ? ex : `.${ex}`, lineCounter)); - lang.filenames.forEach(ex => this.filenameRules.set(ex, lineCounter)); + langExtensions.forEach((lang, id) => { + const langName = lang.aliases.length > 0 ? lang.aliases[0] : id; + const lineCounter = new LineCounter(langName, lang.lineComments, lang.blockComments, lang.blockStrings); + lang.aliases.forEach(v => this.aliasTable.set(v, lineCounter)); + lang.extensions.forEach(v => this.fileextRules.set(v.startsWith('.') ? v : `.${v}`, lineCounter)); + lang.filenames.forEach(v => this.filenameRules.set(v, lineCounter)); }); - - class BlockPattern { - public types: string[] = []; - public patterns: string[][] = []; - } - conf.get< Array >('blockComment', []).forEach(patterns => { - patterns.types.forEach(id => { - const lineCounter = this.getById(id) || this.getByPath(id); - if (lineCounter) { - // log(`addBlockStringRule("${id}", ${tokenPairs.map(t => t.begin + t.end).join('|')}) => [${lineCounter.name}]`); - lineCounter.addBlockStringRule(...patterns.patterns.map(pat => { return {begin: pat[0], end: pat[1]}; })); - } - }); - }); - - // log(`confJsonTable : ${confJsonTable.size} =======================================================================`); - // confJsonTable.forEach((v, n) => { log(`${n}:\n ${JSON.stringify(v)}`); }); - // log(`this.filenameRules : ${this.filenameRules.size} =======================================================================`); - // this.filenameRules.forEach((v, n) => { log(`${n}\t ${JSON.stringify(v)}`); }); - // log(`this.fileextRules : ${this.fileextRules.size} =======================================================================`); - // this.fileextRules.forEach((v, n) => { log(`${n}\t ${JSON.stringify(v)}`); }); - // log(`this.langIdTable : ${this.langIdTable.size} =======================================================================`); - // this.langIdTable.forEach((v, n) => { log(`${n}\t ${JSON.stringify(v)}`); }); - // log(`this.aliasTable : ${this.aliasTable.size} =======================================================================`); - // this.aliasTable.forEach((v, n) => { log(`${n}\t ${JSON.stringify(v)}`); }); } + public entries = () => this.langExtensions; + public getById(langId: string) { return this.langIdTable.get(langId) || this.aliasTable.get(langId); } @@ -527,24 +543,16 @@ class LineCounterTable { return (patType !== undefined) ? this.getById(patType[1]) : undefined; } public getByUri(uri: vscode.Uri) { - return this.getByPath(uri.path); + return this.getByPath(uri.fsPath); } - - // public countById(filepath: string, text: string): {languageId:string, code:number, comment:number, blank:number}|undefined { - // const counter = this.getById(filepath); - // return (counter !== undefined) ? {languageId: counter.languageId, ...counter.count(text)} : undefined; - // } - // public countByPath(filepath: string, text: string): {languageId:string, code:number, comment:number, blank:number}|undefined { - // const counter = this.getByPath(filepath); - // return (counter !== undefined) ? {languageId: counter.languageId, ...counter.count(text)} : undefined; - // } } + async function outputResults(workspaceUri: vscode.Uri, results: Result[], outputDirUri: vscode.Uri, conf: vscode.WorkspaceConfiguration) { const resultTable = new ResultTable(workspaceUri, results, conf.get('printNumberWithCommas', true) ? toStringWithCommas : (obj:any) => obj.toString() ); const endOfLine = conf.get('endOfLine', '\n'); log(`count ${results.length} files`); if (results.length <= 0) { - vscode.window.showErrorMessage(`[${EXTENSION_NAME}] There was no target file.`); + showError(`There was no target file.`); return; } const previewType = conf.get('outputPreviewType', ''); @@ -554,24 +562,24 @@ async function outputResults(workspaceUri: vscode.Uri, results: Result[], output const resultsUri = buildUri(outputDirUri, 'results.txt'); const promise = writeTextFile(resultsUri, resultTable.toTextLines().join(endOfLine)); if (previewType === 'text') { - promise.then(() => showTextFile(resultsUri)).catch(err => console.error(err)); + promise.then(() => showTextFile(resultsUri)).catch(err => showError(`failed to output text.`, err)); } else { - promise.catch(err => console.error(err)); + promise.catch(err => showError(`failed to output text.`, err)); } } if (conf.get('outputAsCSV', true)) { const resultsUri = buildUri(outputDirUri, 'results.csv'); const promise = writeTextFile(resultsUri, resultTable.toCSVLines().join(endOfLine)); if (previewType === 'csv') { - promise.then(() => showTextFile(resultsUri)).catch(err => console.error(err)); + promise.then(() => showTextFile(resultsUri)).catch(err => showError(`failed to output csv.`, err)); } else { - promise.catch(err => console.error(err)); + promise.catch(err => showError(`failed to output csv.`, err)); } } if (conf.get('outputAsMarkdown', true)) { const detailsUri = buildUri(outputDirUri, 'details.md'); const resultsUri = buildUri(outputDirUri, 'results.md'); - const promise = conf.get('outputMarkdownSeparately.', true) + const promise = conf.get('outputMarkdownSeparately', true) ? writeTextFile(detailsUri, [ '# Details', '', @@ -605,9 +613,9 @@ async function outputResults(workspaceUri: vscode.Uri, results: Result[], output ); if (previewType === 'markdown') { promise.then(() => vscode.commands.executeCommand("markdown.showPreview", resultsUri)) - .catch(err => console.error(err)); + .catch(err => showError(`failed to output markdown text.`, err)); } else { - promise.catch(err => console.error(err)); + promise.catch(err => showError(`failed to output markdown text.`, err)); } } } @@ -695,14 +703,14 @@ class ResultTable { .forEach((result) => { let parent = path.dirname(path.relative(this.targetDirPath, result.filename)); while (parent.length >= 0) { - getOrSetFirst(this.dirResultTable, parent, () => new Statistics(parent)).append(result); + getOrSet(this.dirResultTable, parent, () => new Statistics(parent)).append(result); const p = path.dirname(parent); if (p === parent) { break; } parent = p; } - getOrSetFirst(this.langResultTable, result.language, () => new Statistics(result.language)).append(result); + getOrSet(this.langResultTable, result.language, () => new Statistics(result.language)).append(result); this.total.append(result); }); } @@ -765,8 +773,6 @@ class ResultTable { const langFormat = new TextTableFormatter(this.valueToString, {title:'language', width:maxLanglen}, {title:'files', width:10}, {title:'code', width:10}, {title:'comment', width:10}, {title:'blank', width:10}, {title:'total', width:10}); return [ - // '='.repeat(resultFormat.headerLines[0].length), - // EXTENSION_NAME, `Date : ${dateToString(new Date())}`, `Directory : ${this.targetDirPath}`, // `Total : code: ${this.total.code}, comment : ${this.total.comment}, blank : ${this.total.blank}, all ${this.total.total} lines`, @@ -850,7 +856,18 @@ class ResultTable { } -function getOrSetFirst(map: Map, key: K, otherwise: () => V) { +function mapToObject(map: Map) { + const obj: any = {} + map.forEach((v,id)=>{ + obj[id] = v + }) + return obj; +} +function objectToMap(obj: {[key: string]: V}): Map { + return new Map(Object.entries(obj)); +} + +function getOrSet(map: Map, key: K, otherwise: () => V) { let v = map.get(key); if (v === undefined) { v = otherwise(); @@ -858,54 +875,13 @@ function getOrSetFirst(map: Map, key: K, otherwise: () => V) { } return v; } -/* -function makeDirectories(dirpath: string) { - if (fs.existsSync(dirpath)) { - return true; - } - const parent = path.dirname(dirpath); - if ((parent !== dirpath) && makeDirectories(parent)) { - fs.mkdirSync(dirpath); - return true; - } else { - return false; - } -} -function showTextFile(outputFilename: string) { - log(`showTextFile : ${outputFilename}`); - return new Promise((resolve: (editor: vscode.TextEditor)=> void, reject: (err: any) => void) => { - vscode.workspace.openTextDocument(outputFilename) - .then((doc) => { - return vscode.window.showTextDocument(doc, vscode.ViewColumn.One, true); - }, err => { - reject(err); - }).then((editor) => { - resolve(editor); - }, err => { - reject(err); - }); - }); -} -function writeTextFile(outputFilename: string, text: string) { - log(`writeTextFile : ${outputFilename} ${text.length}B`); - return new Promise((resolve: (filename: string)=> void, reject: (err: NodeJS.ErrnoException) => void) => { - fs.writeFile(outputFilename, text, err => { - if (err) { - reject(err); - } else { - resolve(outputFilename); - } - }); - }); -} -*/ function makeDirectories_(dirpath: vscode.Uri, resolve: ()=> void, reject: (reason: string) => void) { // log(`makeDirectories ${dirpath}`); vscode.workspace.fs.stat(dirpath).then((value) => { - if (value.type !== vscode.FileType.File) { - resolve(); - } else { + if (value.type === vscode.FileType.File) { reject(`${dirpath} is not directory.`); + } else { + resolve(); } }, (reason) => { log(`vscode.workspace.fs.stat failed: ${reason}`);