From 6da8ac916a21f7b497eb2975c5b42ebf5563159a Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 29 Aug 2020 10:57:20 -0700 Subject: [PATCH 01/41] [honk] stub out build targets --- Cargo.toml | 1 + honk/CHANGELOG.md | 3 +++ honk/Cargo.toml | 16 ++++++++++++++++ honk/src/lib.rs | 1 + honk/src/main.rs | 3 +++ 5 files changed, 24 insertions(+) create mode 100644 honk/CHANGELOG.md create mode 100644 honk/Cargo.toml create mode 100644 honk/src/lib.rs create mode 100644 honk/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 7bf905bd9..d13ec949c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ members = [ "dom/prettiest", "dom/raf", "dyn-cache", + "honk", "illicit", "illicit/macro", "mox", diff --git a/honk/CHANGELOG.md b/honk/CHANGELOG.md new file mode 100644 index 000000000..1864c6e25 --- /dev/null +++ b/honk/CHANGELOG.md @@ -0,0 +1,3 @@ +# honk changelog + +TODO \ No newline at end of file diff --git a/honk/Cargo.toml b/honk/Cargo.toml new file mode 100644 index 000000000..3aae3a404 --- /dev/null +++ b/honk/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "honk" +version = "0.1.0" +description = "an awful billed system" +categories = ["command-line-utilities", "development-tools::build-utils"] +keywords = ["build", "workflow", "project", "interactive"] +readme = "CHANGELOG.md" + +# update here, update everywhere! +license = "MIT/Apache-2.0" +homepage = "https://moxie.rs" +repository = "https://github.com/anp/moxie.git" +authors = ["Adam Perry "] +edition = "2018" + +[dependencies] diff --git a/honk/src/lib.rs b/honk/src/lib.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/honk/src/lib.rs @@ -0,0 +1 @@ + diff --git a/honk/src/main.rs b/honk/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/honk/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 40f42ccafa6710e14cca9282e720a598fd26f9da Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 29 Aug 2020 11:16:03 -0700 Subject: [PATCH 02/41] [honk] boilerplate vscode extension --- .vscode/launch.json | 28 + honk/editors/vscode/.eslintrc.json | 25 + honk/editors/vscode/.vscodeignore | 7 + honk/editors/vscode/CHANGELOG.md | 9 + honk/editors/vscode/README.md | 16 + honk/editors/vscode/extension.js | 22 + honk/editors/vscode/jsconfig.json | 13 + honk/editors/vscode/package-lock.json | 1824 +++++++++++++++++ honk/editors/vscode/package.json | 40 + honk/editors/vscode/test/runTest.js | 23 + .../vscode/test/suite/extension.test.js | 15 + honk/editors/vscode/test/suite/index.js | 42 + 12 files changed, 2064 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 honk/editors/vscode/.eslintrc.json create mode 100644 honk/editors/vscode/.vscodeignore create mode 100644 honk/editors/vscode/CHANGELOG.md create mode 100644 honk/editors/vscode/README.md create mode 100644 honk/editors/vscode/extension.js create mode 100644 honk/editors/vscode/jsconfig.json create mode 100644 honk/editors/vscode/package-lock.json create mode 100644 honk/editors/vscode/package.json create mode 100644 honk/editors/vscode/test/runTest.js create mode 100644 honk/editors/vscode/test/suite/extension.test.js create mode 100644 honk/editors/vscode/test/suite/index.js diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..cb4ae5871 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +// A launch configuration that launches the extension inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/honk/editors/vscode", + ] + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/honk/editors/vscode", + "--extensionTestsPath=${workspaceFolder}/honk/editors/vscode/test/suite/index" + ] + } + ] +} \ No newline at end of file diff --git a/honk/editors/vscode/.eslintrc.json b/honk/editors/vscode/.eslintrc.json new file mode 100644 index 000000000..d25565bb9 --- /dev/null +++ b/honk/editors/vscode/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "env": { + "browser": false, + "commonjs": true, + "es6": true, + "node": true, + "mocha": true + }, + "parserOptions": { + "ecmaVersion": 2018, + "ecmaFeatures": { + "jsx": true + }, + "sourceType": "module" + }, + "rules": { + "no-const-assign": "warn", + "no-this-before-super": "warn", + "no-undef": "warn", + "no-unreachable": "warn", + "no-unused-vars": "warn", + "constructor-super": "warn", + "valid-typeof": "warn" + } +} diff --git a/honk/editors/vscode/.vscodeignore b/honk/editors/vscode/.vscodeignore new file mode 100644 index 000000000..c64934d23 --- /dev/null +++ b/honk/editors/vscode/.vscodeignore @@ -0,0 +1,7 @@ +.vscode/** +.vscode-test/** +test/** +.gitignore +**/jsconfig.json +**/*.map +**/.eslintrc.json diff --git a/honk/editors/vscode/CHANGELOG.md b/honk/editors/vscode/CHANGELOG.md new file mode 100644 index 000000000..a83fecc36 --- /dev/null +++ b/honk/editors/vscode/CHANGELOG.md @@ -0,0 +1,9 @@ +# honk vscode extension + + + +## [0.0.1] - unreleased + +### [Added] + +- Initial release. \ No newline at end of file diff --git a/honk/editors/vscode/README.md b/honk/editors/vscode/README.md new file mode 100644 index 000000000..4b8ca2b90 --- /dev/null +++ b/honk/editors/vscode/README.md @@ -0,0 +1,16 @@ +# honk vscode extension + +does nothing, go away (for now) + +## Development + +In VSCode, select "Run Extension" in the debug panel and click the run button. To test +changes press the green reload button on the debug toolbar. + +### Tests + +Tests can be run by selecting "Extension Tests" in the debug panel. + +### VSCode API + +The full extension API is visible in the file `node_modules/@types/vscode/index.d.ts`. diff --git a/honk/editors/vscode/extension.js b/honk/editors/vscode/extension.js new file mode 100644 index 000000000..e6db8d074 --- /dev/null +++ b/honk/editors/vscode/extension.js @@ -0,0 +1,22 @@ +const vscode = require('vscode'); + +function activate(context) { + // only executed once when extension is activated + console.log('honkity honk'); + + // TODO make this a panel thingy + let disposable = vscode.commands.registerCommand('honk.boot', function () { + // executed every time command is executed + vscode.window.showInformationMessage('honk'); + }); + + context.subscriptions.push(disposable); +} +exports.activate = activate; + +function deactivate() { } + +module.exports = { + activate, + deactivate +} diff --git a/honk/editors/vscode/jsconfig.json b/honk/editors/vscode/jsconfig.json new file mode 100644 index 000000000..e01e188ed --- /dev/null +++ b/honk/editors/vscode/jsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "checkJs": false, /* Typecheck .js files. */ + "lib": [ + "es6" + ] + }, + "exclude": [ + "node_modules" + ] +} diff --git a/honk/editors/vscode/package-lock.json b/honk/editors/vscode/package-lock.json new file mode 100644 index 000000000..5ad0a8c45 --- /dev/null +++ b/honk/editors/vscode/package-lock.json @@ -0,0 +1,1824 @@ +{ + "name": "honk", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "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.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.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", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mocha": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.3.tgz", + "integrity": "sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==", + "dev": true + }, + "@types/node": { + "version": "14.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.2.tgz", + "integrity": "sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A==", + "dev": true + }, + "@types/vscode": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.48.0.tgz", + "integrity": "sha512-sZJKzsJz1gSoFXcOJWw3fnKl2sseUgZmvB4AJZS+Fea+bC/jfGPVhmFL/FfQHld/TKtukVONsmoD3Pkyx9iadg==", + "dev": true + }, + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "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": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "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" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "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", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "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", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "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.4.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "es-abstract": { + "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.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "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", + "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.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", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.7.0.tgz", + "integrity": "sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.2.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "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 + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "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": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "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", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, + "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" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.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": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "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", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "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.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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-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-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "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.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.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", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "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": "^1.2.5" + } + }, + "mocha": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.1.3.tgz", + "integrity": "sha512-ZbaYib4hT4PpF4bdSO2DohooKXIn4lDeiYqB+vTmCdr6l2woW0b6H3pf5x4sM5nwQMru9RvjjHYWVGltR50ZBw==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.4.2", + "debug": "4.1.1", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "object.assign": "4.1.0", + "promise.allsettled": "1.0.2", + "serialize-javascript": "4.0.0", + "strip-json-comments": "3.0.1", + "supports-color": "7.1.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.0", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "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 + }, + "strip-json-comments": { + "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": "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": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "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.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "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 + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "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" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "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", + "es-abstract": "^1.17.5" + } + }, + "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", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "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" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "vscode-test": { + "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", + "https-proxy-agent": "^2.2.4", + "rimraf": "^2.6.3" + } + }, + "which": { + "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" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "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", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "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", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "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-limit": { + "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==", + "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 + } + } + }, + "yargs-parser": { + "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", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.1.tgz", + "integrity": "sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "decamelize": "^1.2.0", + "flat": "^4.1.0", + "is-plain-obj": "^1.1.0", + "yargs": "^14.2.3" + }, + "dependencies": { + "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-limit": { + "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==", + "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 + }, + "yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "yargs-parser": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + } + } +} diff --git a/honk/editors/vscode/package.json b/honk/editors/vscode/package.json new file mode 100644 index 000000000..c5570c747 --- /dev/null +++ b/honk/editors/vscode/package.json @@ -0,0 +1,40 @@ +{ + "name": "honk-vscode", + "displayName": "honk", + "description": "an awful billed system's vscode extension", + "version": "0.0.1", + "engines": { + "vscode": "^1.48.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "onCommand:honk.boot" + ], + "main": "./extension.js", + "contributes": { + "commands": [ + { + "command": "honk.boot", + "title": "honk" + } + ] + }, + "scripts": { + "lint": "eslint .", + "pretest": "npm run lint", + "test": "node ./test/runTest.js" + }, + "devDependencies": { + "@types/vscode": "^1.48.0", + "@types/glob": "^7.1.3", + "@types/mocha": "^8.0.0", + "@types/node": "^14.0.27", + "eslint": "^7.6.0", + "glob": "^7.1.6", + "mocha": "^8.0.1", + "typescript": "^3.8.3", + "vscode-test": "^1.4.0" + } +} \ No newline at end of file diff --git a/honk/editors/vscode/test/runTest.js b/honk/editors/vscode/test/runTest.js new file mode 100644 index 000000000..587d68c2a --- /dev/null +++ b/honk/editors/vscode/test/runTest.js @@ -0,0 +1,23 @@ +const path = require('path'); + +const { runTests } = require('vscode-test'); + +async function main() { + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, '../'); + + // The path to the extension test script + // Passed to --extensionTestsPath + const extensionTestsPath = path.resolve(__dirname, './suite/index'); + + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + console.error('Failed to run tests'); + process.exit(1); + } +} + +main(); diff --git a/honk/editors/vscode/test/suite/extension.test.js b/honk/editors/vscode/test/suite/extension.test.js new file mode 100644 index 000000000..e8f9042d4 --- /dev/null +++ b/honk/editors/vscode/test/suite/extension.test.js @@ -0,0 +1,15 @@ +const assert = require('assert'); + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +const vscode = require('vscode'); +// const myExtension = require('../extension'); + +suite('Extension Test Suite', () => { + vscode.window.showInformationMessage('Start all tests.'); + + test('Sample test', () => { + assert.equal(-1, [1, 2, 3].indexOf(5)); + assert.equal(-1, [1, 2, 3].indexOf(0)); + }); +}); diff --git a/honk/editors/vscode/test/suite/index.js b/honk/editors/vscode/test/suite/index.js new file mode 100644 index 000000000..f2167599f --- /dev/null +++ b/honk/editors/vscode/test/suite/index.js @@ -0,0 +1,42 @@ +const path = require('path'); +const Mocha = require('mocha'); +const glob = require('glob'); + +function run() { + // Create the mocha test + const mocha = new Mocha({ + ui: 'tdd', + color: true + }); + + const testsRoot = path.resolve(__dirname, '..'); + + return new Promise((c, e) => { + glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { + if (err) { + return e(err); + } + + // Add files to the test suite + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); + + try { + // Run the mocha test + mocha.run(failures => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + console.error(err); + e(err); + } + }); + }); +} + +module.exports = { + run +}; From e2bcd830f265445ce0c04c9b4a7fad1a6bebf555 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 29 Aug 2020 11:21:16 -0700 Subject: [PATCH 03/41] [dom][examples] switch to console_error_panic_hook --- dom/examples/hacking/Cargo.toml | 1 + dom/examples/hacking/src/lib.rs | 4 +--- dom/examples/todo/Cargo.toml | 1 + dom/examples/todo/src/lib.rs | 4 +--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/dom/examples/hacking/Cargo.toml b/dom/examples/hacking/Cargo.toml index 09650d1db..f2f7bd393 100644 --- a/dom/examples/hacking/Cargo.toml +++ b/dom/examples/hacking/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/anp/moxie.git" crate-type = [ "cdylib" ] [dependencies] +console_error_panic_hook = "0.1.6" console_log = "0.2.0" mox = { path = "../../../mox" } moxie-dom = { path = "../../" } diff --git a/dom/examples/hacking/src/lib.rs b/dom/examples/hacking/src/lib.rs index b5f1a56c1..9dbc1a53e 100644 --- a/dom/examples/hacking/src/lib.rs +++ b/dom/examples/hacking/src/lib.rs @@ -11,9 +11,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] pub fn begin() { console_log::init_with_level(tracing::log::Level::Debug).unwrap(); - std::panic::set_hook(Box::new(|info| { - tracing::error!("{:#?}", info); - })); + console_error_panic_hook::set_once(); tracing::info!("mounting moxie-dom to root"); moxie_dom::boot(document().body().unwrap(), root); diff --git a/dom/examples/todo/Cargo.toml b/dom/examples/todo/Cargo.toml index 4d34c3d7d..26817887d 100644 --- a/dom/examples/todo/Cargo.toml +++ b/dom/examples/todo/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/anp/moxie.git" crate-type = [ "cdylib" ] [dependencies] +console_error_panic_hook = "0.1.6" illicit = { path = "../../../illicit" } mox = { path = "../../../mox" } moxie-dom = { path = "../../" } diff --git a/dom/examples/todo/src/lib.rs b/dom/examples/todo/src/lib.rs index cf16afe5d..f0938576f 100644 --- a/dom/examples/todo/src/lib.rs +++ b/dom/examples/todo/src/lib.rs @@ -78,9 +78,7 @@ impl Todo { #[wasm_bindgen(start)] pub fn setup_tracing() { tracing_wasm::set_as_global_default(); - std::panic::set_hook(Box::new(|info| { - error!(?info, "crashed"); - })); + console_error_panic_hook::set_once(); info!("tracing initialized"); } From cf36f39d5149592e54dfdf7cf4a40df26474b555 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 29 Aug 2020 17:10:27 -0700 Subject: [PATCH 04/41] [ts-bindgen] initial impl bits parsing index.d.ts via swc --- .cargo/config.toml | 1 + Cargo.toml | 1 + dom/ts-bindgen/Cargo.toml | 10 ++ dom/ts-bindgen/src/lib.rs | 198 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 dom/ts-bindgen/Cargo.toml create mode 100644 dom/ts-bindgen/src/lib.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 5ecf7fe64..d974d2bc7 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -89,6 +89,7 @@ test-dom-drivertest = "wa-test dom/examples/drivertest" test-dom-hacking = "wa-test dom/examples/hacking" test-dom-todo = "wa-test dom/examples/todo" test-dom-todo-e2e = "ofl serve-then-run --cwd dom/examples/todo/e2e -- npx cypress run" +test-ts-bindgen = "test --package ts-bindgen" # standalones test-dom = "test --package moxie-dom --package ssr-poc --all-targets" diff --git a/Cargo.toml b/Cargo.toml index d13ec949c..ecc788172 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ members = [ "dom/examples/todo", "dom/prettiest", "dom/raf", + "dom/ts-bindgen", "dyn-cache", "honk", "illicit", diff --git a/dom/ts-bindgen/Cargo.toml b/dom/ts-bindgen/Cargo.toml new file mode 100644 index 000000000..1a03250b7 --- /dev/null +++ b/dom/ts-bindgen/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ts-bindgen" +version = "0.1.0" +edition = "2018" + +[dependencies] +swc_common = { version = "0.10.1", features = [ "tty-emitter" ] } +swc_ecma_ast = "0.30.0" +swc_ecma_parser = "0.36.2" +thiserror = "1.0.20" \ No newline at end of file diff --git a/dom/ts-bindgen/src/lib.rs b/dom/ts-bindgen/src/lib.rs new file mode 100644 index 000000000..54d076077 --- /dev/null +++ b/dom/ts-bindgen/src/lib.rs @@ -0,0 +1,198 @@ +use std::{ + env, + fmt::{Debug, Display, Formatter, Result as FmtResult}, + fs, io, + path::Path, + str::FromStr, +}; +use swc_common::BytePos; +use swc_ecma_ast::{Decl, Module, ModuleDecl, ModuleItem, Stmt}; +use swc_ecma_parser::{ + error::Error as SwcError, lexer::input::StringInput, Parser, Syntax, TsConfig, +}; +use thiserror::Error; + +/// Parses the typescript definitions at `input_path` relative to +/// `CARGO_MANIFEST_DIR`, converts them to `wasm-bindgen` import statements, and +/// writes those to `output_path` relative to `OUT_DIR`. +/// +/// In `build.rs`: +/// +/// ```ignore +/// fn main() { +/// ts_bindgen::d_ts_buildscript("relative/path/to/index.d.ts", "index.d.rs").unwrap(); +/// } +/// ``` +/// +/// In `lib.rs`: +/// +/// ```ignore +/// include!(concat!(env!("OUT_DIR"), "/index.d.rs")); +/// ``` +/// +/// For other uses see [`Definitions`] and [`WasmBindgenImports`]. +pub fn d_ts_buildscript( + input_path: impl AsRef, + output_path: impl AsRef, +) -> Result<(), BindingError> { + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").expect("must be run from a build script"); + let input_path = Path::new(&crate_dir).join(input_path.as_ref()); + + let out_dir = env::var_os("OUT_DIR").expect("must be run from a build script"); + let output_path = Path::new(&out_dir).join(output_path.as_ref()); + + println!("cargo:rerun-if-changed={}", input_path.display()); + let input = fs::read_to_string(input_path).map_err(BindingError::ReadInputFile)?; + + let defs: Definitions = input.parse()?; + let imports = defs.import_with_wasm_bindgen()?; + let contents = imports.to_string(); + + fs::write(output_path, contents).map_err(BindingError::WriteOutFile)?; + Ok(()) +} + +#[derive(Debug)] +pub struct Definitions { + defs: Vec, +} + +impl FromStr for Definitions { + type Err = BindingError; + + fn from_str(s: &str) -> Result { + let input = StringInput::new(s, BytePos(0), BytePos(0)); + let mut parser = Parser::new( + Syntax::Typescript(TsConfig { + tsx: false, + decorators: false, + dynamic_import: false, + dts: true, + no_early_errors: true, + }), + input, + None, // TODO figure out what comments do here? + ); + let module = parser.parse_typescript_module()?; + Self::visit(module) + } +} + +impl Definitions { + pub fn visit(module: Module) -> Result { + let mut defs = vec![]; + for item in module.body { + match item { + ModuleItem::ModuleDecl(decl) => match decl { + ModuleDecl::Import(import) => println!("imports?"), + ModuleDecl::ExportDecl(decl) => println!("export decl"), + ModuleDecl::ExportNamed(named) => println!("export named"), + ModuleDecl::ExportDefaultDecl(default_decl) => println!("export default decl"), + ModuleDecl::ExportDefaultExpr(default_expr) => println!("export default expr"), + ModuleDecl::ExportAll(export_all) => println!("export all"), + ModuleDecl::TsImportEquals(ts_import) => println!("ts import ="), + ModuleDecl::TsExportAssignment(ts_export) => println!("ts export assignment"), + ModuleDecl::TsNamespaceExport(ts_ns_export) => println!("ts ns export"), + }, + ModuleItem::Stmt(Stmt::Decl(decl)) => { + println!("decl"); + } + ModuleItem::Stmt(stmt) => { + println!("skipping statement TODO what to do with these? {:#?}", stmt); + } + } + } + Ok(Self { defs }) + } + + pub fn import_with_wasm_bindgen(&self) -> Result { + Ok(WasmBindgenImports {}) + } +} + +#[derive(Debug)] +enum Defn { + // TODO populate these! + TypeAlias, + Interface, + Class, + Enum, + Import, + Namespace, + Module, + Function, +} + +pub struct WasmBindgenImports { + // TODO +} + +impl Display for WasmBindgenImports { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + // write!(f, "") + todo!() + } +} + +#[derive(Debug, Error)] +pub enum BindingError { + #[error("reading input failed")] + ReadInputFile(io::Error), + + #[error("parsing")] + ParseInputFile { source: ParseError }, + + #[error("writing output failed")] + WriteOutFile(io::Error), +} + +impl From for BindingError { + fn from(e: SwcError) -> Self { + BindingError::ParseInputFile { source: e.into() } + } +} + +#[derive(Error)] +pub struct ParseError { + e: SwcError, +} + +impl ParseError { + fn to_stderr(&self) { + use swc_common::errors::{ColorConfig, EmitterWriter, Handler, HandlerFlags}; + let emitter = EmitterWriter::stderr( + ColorConfig::Auto, + None, // source maps + false, // short_message + true, // teach + ); + let handler = Handler::with_emitter_and_flags(Box::new(emitter), HandlerFlags { + can_emit_warnings: true, + treat_err_as_bug: true, + dont_buffer_diagnostics: true, + report_delayed_bugs: false, + external_macro_backtrace: false, // lol + }); + self.e.clone().into_diagnostic(&handler).emit(); + } +} + +impl Debug for ParseError { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + self.to_stderr(); + write!(f, "ParseError(see stderr)") + } +} + +impl Display for ParseError { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + self.to_stderr(); + write!(f, "Parsing error (see stderr for details)") + } +} + +impl From for ParseError { + fn from(e: SwcError) -> Self { + ParseError { e } + } +} From 29d648a823238c6b43858c7c8d62610dead02298 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 30 Aug 2020 11:16:50 -0700 Subject: [PATCH 05/41] [ts-bindgen] reorganize crate --- dom/ts-bindgen/Cargo.toml | 2 + dom/ts-bindgen/src/error.rs | 69 ++++++++++++ dom/ts-bindgen/src/lib.rs | 174 +++---------------------------- dom/ts-bindgen/src/typescript.rs | 46 ++++++++ dom/ts-bindgen/src/wasm.rs | 11 ++ 5 files changed, 141 insertions(+), 161 deletions(-) create mode 100644 dom/ts-bindgen/src/error.rs create mode 100644 dom/ts-bindgen/src/typescript.rs create mode 100644 dom/ts-bindgen/src/wasm.rs diff --git a/dom/ts-bindgen/Cargo.toml b/dom/ts-bindgen/Cargo.toml index 1a03250b7..4e528752e 100644 --- a/dom/ts-bindgen/Cargo.toml +++ b/dom/ts-bindgen/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2018" [dependencies] +proc-macro2 = "1" +quote = "1" swc_common = { version = "0.10.1", features = [ "tty-emitter" ] } swc_ecma_ast = "0.30.0" swc_ecma_parser = "0.36.2" diff --git a/dom/ts-bindgen/src/error.rs b/dom/ts-bindgen/src/error.rs new file mode 100644 index 000000000..bbaccda4c --- /dev/null +++ b/dom/ts-bindgen/src/error.rs @@ -0,0 +1,69 @@ +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + io, +}; +use swc_ecma_parser::error::Error as SwcError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum BindingError { + #[error("reading input failed")] + ReadInputFile(io::Error), + + #[error("parsing")] + ParseInputFile { source: ParseError }, + + #[error("writing output failed")] + WriteOutFile(io::Error), +} + +impl From for BindingError { + fn from(e: SwcError) -> Self { + BindingError::ParseInputFile { source: e.into() } + } +} + +#[derive(Error)] +pub struct ParseError { + e: SwcError, +} + +impl ParseError { + fn to_stderr(&self) { + use swc_common::errors::{ColorConfig, EmitterWriter, Handler, HandlerFlags}; + let emitter = EmitterWriter::stderr( + ColorConfig::Auto, + None, // source maps + false, // short_message + true, // teach + ); + let handler = Handler::with_emitter_and_flags(Box::new(emitter), HandlerFlags { + can_emit_warnings: true, + treat_err_as_bug: true, + dont_buffer_diagnostics: true, + report_delayed_bugs: false, + external_macro_backtrace: false, // lol + }); + self.e.clone().into_diagnostic(&handler).emit(); + } +} + +impl Debug for ParseError { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + self.to_stderr(); + write!(f, "ParseError(see stderr)") + } +} + +impl Display for ParseError { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + self.to_stderr(); + write!(f, "Parsing error (see stderr for details)") + } +} + +impl From for ParseError { + fn from(e: SwcError) -> Self { + ParseError { e } + } +} diff --git a/dom/ts-bindgen/src/lib.rs b/dom/ts-bindgen/src/lib.rs index 54d076077..d0da35800 100644 --- a/dom/ts-bindgen/src/lib.rs +++ b/dom/ts-bindgen/src/lib.rs @@ -1,16 +1,12 @@ -use std::{ - env, - fmt::{Debug, Display, Formatter, Result as FmtResult}, - fs, io, - path::Path, - str::FromStr, -}; -use swc_common::BytePos; -use swc_ecma_ast::{Decl, Module, ModuleDecl, ModuleItem, Stmt}; -use swc_ecma_parser::{ - error::Error as SwcError, lexer::input::StringInput, Parser, Syntax, TsConfig, -}; -use thiserror::Error; +use quote::ToTokens; +use std::{env, fs, path::Path}; + +pub mod error; +pub mod typescript; +pub mod wasm; + +use error::BindingError; +use typescript::TsModule; /// Parses the typescript definitions at `input_path` relative to /// `CARGO_MANIFEST_DIR`, converts them to `wasm-bindgen` import statements, and @@ -30,7 +26,8 @@ use thiserror::Error; /// include!(concat!(env!("OUT_DIR"), "/index.d.rs")); /// ``` /// -/// For other uses see [`Definitions`] and [`WasmBindgenImports`]. +/// For other uses see [`typescript::TsModule`] and TODO add back type for +/// wasm-bindgen. pub fn d_ts_buildscript( input_path: impl AsRef, output_path: impl AsRef, @@ -44,155 +41,10 @@ pub fn d_ts_buildscript( println!("cargo:rerun-if-changed={}", input_path.display()); let input = fs::read_to_string(input_path).map_err(BindingError::ReadInputFile)?; - let defs: Definitions = input.parse()?; + let defs: TsModule = input.parse()?; let imports = defs.import_with_wasm_bindgen()?; - let contents = imports.to_string(); + let contents = imports.to_token_stream().to_string(); fs::write(output_path, contents).map_err(BindingError::WriteOutFile)?; Ok(()) } - -#[derive(Debug)] -pub struct Definitions { - defs: Vec, -} - -impl FromStr for Definitions { - type Err = BindingError; - - fn from_str(s: &str) -> Result { - let input = StringInput::new(s, BytePos(0), BytePos(0)); - let mut parser = Parser::new( - Syntax::Typescript(TsConfig { - tsx: false, - decorators: false, - dynamic_import: false, - dts: true, - no_early_errors: true, - }), - input, - None, // TODO figure out what comments do here? - ); - let module = parser.parse_typescript_module()?; - Self::visit(module) - } -} - -impl Definitions { - pub fn visit(module: Module) -> Result { - let mut defs = vec![]; - for item in module.body { - match item { - ModuleItem::ModuleDecl(decl) => match decl { - ModuleDecl::Import(import) => println!("imports?"), - ModuleDecl::ExportDecl(decl) => println!("export decl"), - ModuleDecl::ExportNamed(named) => println!("export named"), - ModuleDecl::ExportDefaultDecl(default_decl) => println!("export default decl"), - ModuleDecl::ExportDefaultExpr(default_expr) => println!("export default expr"), - ModuleDecl::ExportAll(export_all) => println!("export all"), - ModuleDecl::TsImportEquals(ts_import) => println!("ts import ="), - ModuleDecl::TsExportAssignment(ts_export) => println!("ts export assignment"), - ModuleDecl::TsNamespaceExport(ts_ns_export) => println!("ts ns export"), - }, - ModuleItem::Stmt(Stmt::Decl(decl)) => { - println!("decl"); - } - ModuleItem::Stmt(stmt) => { - println!("skipping statement TODO what to do with these? {:#?}", stmt); - } - } - } - Ok(Self { defs }) - } - - pub fn import_with_wasm_bindgen(&self) -> Result { - Ok(WasmBindgenImports {}) - } -} - -#[derive(Debug)] -enum Defn { - // TODO populate these! - TypeAlias, - Interface, - Class, - Enum, - Import, - Namespace, - Module, - Function, -} - -pub struct WasmBindgenImports { - // TODO -} - -impl Display for WasmBindgenImports { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - // write!(f, "") - todo!() - } -} - -#[derive(Debug, Error)] -pub enum BindingError { - #[error("reading input failed")] - ReadInputFile(io::Error), - - #[error("parsing")] - ParseInputFile { source: ParseError }, - - #[error("writing output failed")] - WriteOutFile(io::Error), -} - -impl From for BindingError { - fn from(e: SwcError) -> Self { - BindingError::ParseInputFile { source: e.into() } - } -} - -#[derive(Error)] -pub struct ParseError { - e: SwcError, -} - -impl ParseError { - fn to_stderr(&self) { - use swc_common::errors::{ColorConfig, EmitterWriter, Handler, HandlerFlags}; - let emitter = EmitterWriter::stderr( - ColorConfig::Auto, - None, // source maps - false, // short_message - true, // teach - ); - let handler = Handler::with_emitter_and_flags(Box::new(emitter), HandlerFlags { - can_emit_warnings: true, - treat_err_as_bug: true, - dont_buffer_diagnostics: true, - report_delayed_bugs: false, - external_macro_backtrace: false, // lol - }); - self.e.clone().into_diagnostic(&handler).emit(); - } -} - -impl Debug for ParseError { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - self.to_stderr(); - write!(f, "ParseError(see stderr)") - } -} - -impl Display for ParseError { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - self.to_stderr(); - write!(f, "Parsing error (see stderr for details)") - } -} - -impl From for ParseError { - fn from(e: SwcError) -> Self { - ParseError { e } - } -} diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs new file mode 100644 index 000000000..34ef5d800 --- /dev/null +++ b/dom/ts-bindgen/src/typescript.rs @@ -0,0 +1,46 @@ +use crate::{error::BindingError, wasm::WasmBindgenImport}; +use std::{convert::TryFrom, fmt::Debug, str::FromStr}; +use swc_common::BytePos; +use swc_ecma_ast::*; +use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; + +pub fn parse_d_ts(contents: &str) -> Result { + let input = StringInput::new(contents, BytePos(0), BytePos(0)); + let mut parser = Parser::new( + Syntax::Typescript(TsConfig { + tsx: false, + decorators: false, + dynamic_import: false, + dts: true, + no_early_errors: true, + }), + input, + None, // TODO figure out what comments do here? + ); + Ok(parser.parse_typescript_module()?) +} + +#[derive(Debug)] +pub struct TsModule {} + +impl FromStr for TsModule { + type Err = BindingError; + + fn from_str(s: &str) -> Result { + Self::try_from(parse_d_ts(s)?) + } +} + +impl TryFrom for TsModule { + type Error = BindingError; + + fn try_from(_module: Module) -> Result { + todo!() + } +} + +impl TsModule { + pub fn import_with_wasm_bindgen(&self) -> Result { + todo!() + } +} diff --git a/dom/ts-bindgen/src/wasm.rs b/dom/ts-bindgen/src/wasm.rs new file mode 100644 index 000000000..b87154f98 --- /dev/null +++ b/dom/ts-bindgen/src/wasm.rs @@ -0,0 +1,11 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +#[derive(Debug)] +pub struct WasmBindgenImport {} + +impl ToTokens for WasmBindgenImport { + fn to_tokens(&self, _ts: &mut TokenStream) { + todo!() + } +} From 37a789d30ddd07bb88d84ac3025c5543ff7d2fa4 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 09:11:04 -0700 Subject: [PATCH 06/41] [ts-bindgen] start of an IR for TS types --- dom/ts-bindgen/src/error.rs | 19 ++- dom/ts-bindgen/src/typescript.rs | 263 +++++++++++++++++++++++++++++-- 2 files changed, 265 insertions(+), 17 deletions(-) diff --git a/dom/ts-bindgen/src/error.rs b/dom/ts-bindgen/src/error.rs index bbaccda4c..81b019c39 100644 --- a/dom/ts-bindgen/src/error.rs +++ b/dom/ts-bindgen/src/error.rs @@ -10,16 +10,25 @@ pub enum BindingError { #[error("reading input failed")] ReadInputFile(io::Error), - #[error("parsing")] - ParseInputFile { source: ParseError }, - #[error("writing output failed")] WriteOutFile(io::Error), + + #[error("processing typescript failed")] + Typescript { + #[from] + source: TypescriptError, + }, +} + +#[derive(Debug, Error)] +pub enum TypescriptError { + #[error("parsing failed")] + ParseInputFile { source: ParseError }, } -impl From for BindingError { +impl From for TypescriptError { fn from(e: SwcError) -> Self { - BindingError::ParseInputFile { source: e.into() } + TypescriptError::ParseInputFile { source: e.into() } } } diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 34ef5d800..c2f5fae8d 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -1,10 +1,10 @@ -use crate::{error::BindingError, wasm::WasmBindgenImport}; -use std::{convert::TryFrom, fmt::Debug, str::FromStr}; +use crate::{error::TypescriptError, wasm::WasmBindgenImport}; +use std::{collections::BTreeMap, fmt::Debug, str::FromStr}; use swc_common::BytePos; use swc_ecma_ast::*; use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; -pub fn parse_d_ts(contents: &str) -> Result { +pub fn parse_d_ts(contents: &str) -> Result { let input = StringInput::new(contents, BytePos(0), BytePos(0)); let mut parser = Parser::new( Syntax::Typescript(TsConfig { @@ -21,26 +21,265 @@ pub fn parse_d_ts(contents: &str) -> Result { } #[derive(Debug)] -pub struct TsModule {} +pub struct TsModule { + children: BTreeMap, + classes: BTreeMap, + enums: BTreeMap, +} impl FromStr for TsModule { - type Err = BindingError; + type Err = TypescriptError; fn from_str(s: &str) -> Result { - Self::try_from(parse_d_ts(s)?) + Ok(Self::from(parse_d_ts(s)?)) } } -impl TryFrom for TsModule { - type Error = BindingError; +impl From for TsModule { + fn from(module: Module) -> Self { + let mut new = TsModule::blank(); + new.add_module_contents(module.body); + new + } +} + +impl TsModule { + fn blank() -> Self { + Self { + children: Default::default(), + classes: Default::default(), + enums: Default::default(), + } + } + + fn add_module_contents(&mut self, contents: Vec) { + for item in contents { + match item { + ModuleItem::ModuleDecl(decl) => match decl { + ModuleDecl::Import(import) => self.add_import(import), + ModuleDecl::ExportDecl(export) => self.add_decl(export.decl), + ModuleDecl::ExportNamed(named) => self.add_named_export(named), + ModuleDecl::ExportDefaultDecl(default_decl) => { + self.add_default_export(default_decl) + } + ModuleDecl::ExportDefaultExpr(expr) => self.add_default_export_expr(expr), + ModuleDecl::ExportAll(export_all) => self.add_export_all(export_all), + + ModuleDecl::TsImportEquals(ts_import) => self.add_import_equals(ts_import), + ModuleDecl::TsExportAssignment(ts_export) => self.add_export_assign(ts_export), + ModuleDecl::TsNamespaceExport(ts_ns_export) => { + self.add_namespace_export(ts_ns_export) + } + }, + ModuleItem::Stmt(stmt) => self.add_stmt(stmt), + } + } + } + + fn add_import(&mut self, _import: ImportDecl) { + println!("TODO support imports"); + } + + pub fn add_named_export(&mut self, _named: NamedExport) { + println!("TODO support re-exports"); + } + + pub fn add_default_export(&mut self, _default_decl: ExportDefaultDecl) { + println!("TODO export default decl"); + } + + pub fn add_default_export_expr(&mut self, _default_expr: ExportDefaultExpr) { + println!("TODO export default expr"); + } + + pub fn add_export_all(&mut self, _export_all: ExportAll) { + println!("TODO export all"); + } + + pub fn add_import_equals(&mut self, _ts_import: TsImportEqualsDecl) { + println!("TODO ts import"); + } + + pub fn add_export_assign(&mut self, _ts_export: TsExportAssignment) { + println!("TODO export assignment"); + } + + pub fn add_namespace_export(&mut self, _ts_ns_export: TsNamespaceExportDecl) { + println!("TODO typescript namespace export"); + } + + fn add_stmt(&mut self, stmt: Stmt) { + match stmt { + Stmt::Decl(decl) => self.add_decl(decl), + _ => { + println!("TODO non-decl statements"); + } + } + } + + fn add_decl(&mut self, decl: Decl) { + match decl { + Decl::Class(class) => self.add_class(class), + Decl::TsInterface(interface) => self.add_interface(interface), + Decl::TsTypeAlias(alias) => self.add_alias(alias), + Decl::TsEnum(ts_enum) => self.add_enum(ts_enum), + Decl::TsModule(TsModuleDecl { id, body, .. }) => self.add_ts_module(id, body), + Decl::Fn(fun) => self.add_function(fun), + Decl::Var(var) => self.add_var(var), + } + } + + fn add_var(&mut self, var: VarDecl) { + for decl in var.decls { + let name = match decl.name { + Pat::Ident(n) => n.sym.to_string(), + other => { + todo!("i guess implement support for assignments to {:?}", other); + } + }; + + if let Some(init) = decl.init { + todo!("i guess support initializing {:?} {} {:?}", &var.kind, name, init); + } + } + } + + fn add_function(&mut self, _fun: FnDecl) { + println!("TODO functions"); + } + + fn add_class(&mut self, class: ClassDecl) { + let class: Class = class.into(); + let name = class.name.clone(); + self.classes.insert(name, class); + } + + fn add_interface(&mut self, _interface: TsInterfaceDecl) { + println!("TODO interfaces"); + } + + fn add_alias(&mut self, _alias: TsTypeAliasDecl) { + println!("TODO ts aliases"); + } + + fn add_enum(&mut self, decl: TsEnumDecl) { + let new: Enum = decl.into(); + let name = new.name.clone(); + self.enums.insert(name, new); + } + + fn add_ts_module(&mut self, id: TsModuleName, body: Option) { + let new_child = self.children.entry(module_name(&id)).or_insert_with(TsModule::blank); + + match body { + Some(TsNamespaceBody::TsModuleBlock(block)) => { + new_child.add_module_contents(block.body); + } + Some(TsNamespaceBody::TsNamespaceDecl(TsNamespaceDecl { id, body, .. })) => { + new_child.add_ts_module(TsModuleName::Ident(id), Some(*body)); + } + None => (), + } + } +} + +#[derive(Debug)] +struct Class { + name: String, + constructor: Option<()>, + properties: BTreeMap, + methods: BTreeMap, +} + +impl From for Class { + fn from(class: ClassDecl) -> Self { + let mut new = Class { + name: class.ident.sym.to_string(), + constructor: None, + properties: Default::default(), + methods: Default::default(), + }; + + // TODO type params + // TODO super class & type params + // TODO implemented interfaces + + for member in class.class.body { + match member { + ClassMember::Constructor(ctor) => new.set_constructor(ctor), + ClassMember::Method(method) => new.add_method(method), + ClassMember::ClassProp(prop) => new.add_property(prop), + ClassMember::PrivateMethod(_) => { + println!("TODO figure out if we care about private methods") + } + ClassMember::PrivateProp(_) => { + println!("TODO figure out if we care about private properties") + } + ClassMember::TsIndexSignature(_) => println!("TODO figure out ts index signatures"), + ClassMember::Empty(_) => (), + } + } + + new + } +} + +impl Class { + fn set_constructor(&mut self, ctor: Constructor) { + println!("TODO constructors"); + } + + fn add_method(&mut self, method: ClassMethod) { + println!("TODO class methods"); + } + + fn add_property(&mut self, prop: ClassProp) { + println!("TODO class properties"); + } +} + +#[derive(Debug)] +struct Enum { + name: String, + members: Vec, +} + +impl From for Enum { + fn from(decl: TsEnumDecl) -> Self { + let name = decl.id.sym.to_string(); + let members = decl + .members + .into_iter() + .map(|member| { + let member_name = member_name(&member.id); + if member.init.is_some() { + println!("TODO enum member init {}.{}", &name, &member_name); + } + member_name + }) + .collect(); + Enum { name, members } + } +} + +fn member_name(id: &TsEnumMemberId) -> String { + match id { + TsEnumMemberId::Ident(i) => &i.sym, + TsEnumMemberId::Str(s) => &s.value, + } + .to_string() +} - fn try_from(_module: Module) -> Result { - todo!() +fn module_name(id: &TsModuleName) -> String { + match id { + TsModuleName::Ident(i) => &i.sym, + TsModuleName::Str(s) => &s.value, } + .to_string() } impl TsModule { - pub fn import_with_wasm_bindgen(&self) -> Result { - todo!() + pub fn import_with_wasm_bindgen(&self) -> Result { + todo!("{:#?}", self) } } From 12fe94f26ef673862151053926965fe54b0d845d Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 11:08:40 -0700 Subject: [PATCH 07/41] [ts-bindgen] begging of ctors and methods, better Debug impls --- dom/ts-bindgen/src/typescript.rs | 231 ++++++++++++++++++++++++++----- 1 file changed, 197 insertions(+), 34 deletions(-) diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index c2f5fae8d..59eabadbf 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -1,5 +1,9 @@ use crate::{error::TypescriptError, wasm::WasmBindgenImport}; -use std::{collections::BTreeMap, fmt::Debug, str::FromStr}; +use std::{ + collections::BTreeMap, + fmt::{Debug, Display, Formatter, Result as FmtResult}, + str::FromStr, +}; use swc_common::BytePos; use swc_ecma_ast::*; use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; @@ -20,11 +24,43 @@ pub fn parse_d_ts(contents: &str) -> Result { Ok(parser.parse_typescript_module()?) } -#[derive(Debug)] +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] +struct Name(String); + +impl From for Name { + fn from(s: String) -> Self { + Name(s.to_string()) + } +} + +impl Debug for Name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(&self.0) + } +} + +impl Display for Name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(&self.0) + } +} + pub struct TsModule { - children: BTreeMap, - classes: BTreeMap, - enums: BTreeMap, + enums: Vec, + classes: Vec, + children: BTreeMap, +} + +impl Debug for TsModule { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut module = f.debug_set(); + + module.entries(&self.enums); + module.entries(&self.classes); + module.entries(&self.children); + + module.finish() + } } impl FromStr for TsModule { @@ -132,14 +168,14 @@ impl TsModule { fn add_var(&mut self, var: VarDecl) { for decl in var.decls { let name = match decl.name { - Pat::Ident(n) => n.sym.to_string(), + Pat::Ident(n) => Name::from(n.sym.to_string()), other => { todo!("i guess implement support for assignments to {:?}", other); } }; if let Some(init) = decl.init { - todo!("i guess support initializing {:?} {} {:?}", &var.kind, name, init); + todo!("i guess support initializing {:?} {:?} {:?}", &var.kind, name, init); } } } @@ -149,9 +185,7 @@ impl TsModule { } fn add_class(&mut self, class: ClassDecl) { - let class: Class = class.into(); - let name = class.name.clone(); - self.classes.insert(name, class); + self.classes.push(class.into()); } fn add_interface(&mut self, _interface: TsInterfaceDecl) { @@ -163,9 +197,7 @@ impl TsModule { } fn add_enum(&mut self, decl: TsEnumDecl) { - let new: Enum = decl.into(); - let name = new.name.clone(); - self.enums.insert(name, new); + self.enums.push(decl.into()); } fn add_ts_module(&mut self, id: TsModuleName, body: Option) { @@ -183,20 +215,17 @@ impl TsModule { } } -#[derive(Debug)] struct Class { - name: String, - constructor: Option<()>, - properties: BTreeMap, - methods: BTreeMap, + name: Name, + constructors: Vec, + methods: Vec, } impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { - name: class.ident.sym.to_string(), - constructor: None, - properties: Default::default(), + name: class.ident.sym.to_string().into(), + constructors: Default::default(), methods: Default::default(), }; @@ -206,9 +235,11 @@ impl From for Class { for member in class.class.body { match member { - ClassMember::Constructor(ctor) => new.set_constructor(ctor), + ClassMember::Constructor(ctor) => new.add_constructor(ctor), ClassMember::Method(method) => new.add_method(method), - ClassMember::ClassProp(prop) => new.add_property(prop), + ClassMember::ClassProp(_) => { + println!("TODO figure out if we care about class properties") + } ClassMember::PrivateMethod(_) => { println!("TODO figure out if we care about private methods") } @@ -225,35 +256,156 @@ impl From for Class { } impl Class { - fn set_constructor(&mut self, ctor: Constructor) { - println!("TODO constructors"); + fn add_constructor(&mut self, ctor: Constructor) { + self.constructors.push(Ctor { + for_class: self.name.clone(), + params: ctor + .params + .into_iter() + .map(|param| match param { + ParamOrTsParamProp::Param(p) => p.into(), + ParamOrTsParamProp::TsParamProp(t) => { + todo!("support ts 'param props' from swc ast {:#?}", t); + } + }) + .collect(), + }); } fn add_method(&mut self, method: ClassMethod) { - println!("TODO class methods"); + self.methods.push(method.into()); } +} + +impl Debug for Class { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut f = f.debug_struct(&self.name.0); + + for ctor in &self.constructors { + f.field("constructor", &ctor); // TODO better way to structure these? + } - fn add_property(&mut self, prop: ClassProp) { - println!("TODO class properties"); + for method in &self.methods { + f.field("method", &method); // TODO better way to structure these? + } + + f.finish() + } +} + +struct Ctor { + for_class: Name, + params: Vec, +} + +impl Debug for Ctor { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let new = format!("new {}", &self.for_class); + let mut f = f.debug_tuple(&new); + + for p in &self.params { + f.field(p); + } + + f.finish() + } +} + +struct Method { + name: Name, + params: Vec, + returns: Option, +} + +impl From for Method { + fn from(method: ClassMethod) -> Self { + let name = prop_name(method.key); + + let mut params = vec![]; + // TODO iterate over params + + let returns = None; // TODO + + Self { name, params, returns } + } +} + +impl Debug for Method { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut tup = f.debug_tuple(&self.name.0); + for p in &self.params { + tup.field(p); + } + tup.finish()?; + + if let Some(ret) = &self.returns { write!(f, " -> {:?}", ret) } else { Ok(()) } + } +} + +struct TsParam { + name: Name, + optional: bool, + ty: Ty, +} + +impl From for TsParam { + fn from(param: Param) -> TsParam { + match param.pat { + Pat::Ident(i) => { + let name = i.sym.to_string().into(); + let ty = i.type_ann.into(); + Self { name, ty, optional: i.optional } + } + other => todo!("other parameter types like {:#?}", other), + } + } +} + +impl Debug for TsParam { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let optional = if self.optional { "?" } else { "" }; + write!(f, "{}{}: {:?}", &self.name, optional, &self.ty) + } +} + +#[derive(Debug)] +struct Ty { + // TODO figure out a repr for not-yet-resolved types +} + +impl From for Ty { + fn from(_ty: TsType) -> Ty { + // TODO ...stuff + Ty {} + } +} + +impl From> for Ty { + fn from(ann: Option) -> Ty { + if let Some(ann) = ann { + (*ann.type_ann).into() + } else { + Ty {} // TODO make an Any/universal type i guess? + } } } #[derive(Debug)] struct Enum { - name: String, - members: Vec, + name: Name, + members: Vec, } impl From for Enum { fn from(decl: TsEnumDecl) -> Self { - let name = decl.id.sym.to_string(); + let name = decl.id.sym.to_string().into(); let members = decl .members .into_iter() .map(|member| { let member_name = member_name(&member.id); if member.init.is_some() { - println!("TODO enum member init {}.{}", &name, &member_name); + println!("TODO enum member init {:?}.{:?}", &name, &member_name); } member_name }) @@ -262,20 +414,31 @@ impl From for Enum { } } -fn member_name(id: &TsEnumMemberId) -> String { +fn member_name(id: &TsEnumMemberId) -> Name { match id { TsEnumMemberId::Ident(i) => &i.sym, TsEnumMemberId::Str(s) => &s.value, } .to_string() + .into() } -fn module_name(id: &TsModuleName) -> String { +fn module_name(id: &TsModuleName) -> Name { match id { TsModuleName::Ident(i) => &i.sym, TsModuleName::Str(s) => &s.value, } .to_string() + .into() +} + +fn prop_name(key: PropName) -> Name { + match key { + PropName::Ident(i) => i.sym.to_string().into(), + PropName::Str(s) => s.value.to_string().into(), + PropName::Num(n) => n.value.to_string().into(), + PropName::Computed(c) => todo!("support computed property names: {:#?}", c), + } } impl TsModule { From db3cc4dd3f79936cde9c93aa045ee53665b4202c Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 11:46:58 -0700 Subject: [PATCH 08/41] [ts-bindgen] unify ctor and function types, improve module debug --- dom/ts-bindgen/src/typescript.rs | 129 ++++++++++++++++--------------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 59eabadbf..182cbdd24 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -53,13 +53,8 @@ pub struct TsModule { impl Debug for TsModule { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut module = f.debug_set(); - - module.entries(&self.enums); - module.entries(&self.classes); - module.entries(&self.children); - - module.finish() + f.debug_list().entries(&self.enums).entries(&self.classes).finish()?; + f.debug_map().entries(&self.children).finish() } } @@ -217,8 +212,9 @@ impl TsModule { struct Class { name: Name, - constructors: Vec, - methods: Vec, + constructors: Vec, + statics: BTreeMap, + methods: BTreeMap, } impl From for Class { @@ -226,6 +222,7 @@ impl From for Class { let mut new = Class { name: class.ident.sym.to_string().into(), constructors: Default::default(), + statics: Default::default(), methods: Default::default(), }; @@ -256,24 +253,23 @@ impl From for Class { } impl Class { + fn ty(&self) -> Ty { + Ty {} // TODO return *this*'s type + } + fn add_constructor(&mut self, ctor: Constructor) { - self.constructors.push(Ctor { - for_class: self.name.clone(), - params: ctor - .params - .into_iter() - .map(|param| match param { - ParamOrTsParamProp::Param(p) => p.into(), - ParamOrTsParamProp::TsParamProp(t) => { - todo!("support ts 'param props' from swc ast {:#?}", t); - } - }) - .collect(), - }); + self.constructors.push(Func::ctor(&self, ctor.params)); } fn add_method(&mut self, method: ClassMethod) { - self.methods.push(method.into()); + let name = prop_name(method.key); + let func = Func::from(method.function); + + if method.is_static { + self.statics.insert(name, func); + } else { + self.methods.insert(name, func); + } } } @@ -282,61 +278,56 @@ impl Debug for Class { let mut f = f.debug_struct(&self.name.0); for ctor in &self.constructors { - f.field("constructor", &ctor); // TODO better way to structure these? + f.field("constructor", &ctor); } - for method in &self.methods { - f.field("method", &method); // TODO better way to structure these? + for (name, function) in &self.methods { + f.field(&name.0, function); } f.finish() } } -struct Ctor { - for_class: Name, +struct Func { params: Vec, + returns: Option, } -impl Debug for Ctor { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let new = format!("new {}", &self.for_class); - let mut f = f.debug_tuple(&new); - - for p in &self.params { - f.field(p); +impl Func { + fn ctor(class: &Class, params: Vec) -> Self { + Self { + params: params + .into_iter() + .map(|param| match param { + ParamOrTsParamProp::Param(p) => p.into(), + ParamOrTsParamProp::TsParamProp(t) => { + todo!("support ts 'param props' from swc ast {:#?}", t); + } + }) + .collect(), + returns: Some(class.ty()), } - - f.finish() } } -struct Method { - name: Name, - params: Vec, - returns: Option, -} - -impl From for Method { - fn from(method: ClassMethod) -> Self { - let name = prop_name(method.key); - - let mut params = vec![]; - // TODO iterate over params - - let returns = None; // TODO - - Self { name, params, returns } +impl From for Func { + fn from(function: Function) -> Self { + Self { params: function.params.into_iter().map(From::from).collect(), returns: None } } } -impl Debug for Method { +impl Debug for Func { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut tup = f.debug_tuple(&self.name.0); - for p in &self.params { - tup.field(p); + if self.params.is_empty() { + write!(f, "()")?; + } else { + let mut tup = f.debug_tuple(""); + for p in &self.params { + tup.field(p); + } + tup.finish()?; } - tup.finish()?; if let Some(ret) = &self.returns { write!(f, " -> {:?}", ret) } else { Ok(()) } } @@ -345,6 +336,7 @@ impl Debug for Method { struct TsParam { name: Name, optional: bool, + rest: bool, ty: Ty, } @@ -354,7 +346,12 @@ impl From for TsParam { Pat::Ident(i) => { let name = i.sym.to_string().into(); let ty = i.type_ann.into(); - Self { name, ty, optional: i.optional } + Self { name, ty, rest: false, optional: i.optional } + } + Pat::Rest(r) => { + let name = r.arg.expect_ident().sym.to_string().into(); + let ty = r.type_ann.into(); + Self { name, ty, rest: true, optional: false } } other => todo!("other parameter types like {:#?}", other), } @@ -363,8 +360,9 @@ impl From for TsParam { impl Debug for TsParam { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let rest = if self.rest { "..." } else { "" }; let optional = if self.optional { "?" } else { "" }; - write!(f, "{}{}: {:?}", &self.name, optional, &self.ty) + write!(f, "{}{}{}: {:?}", rest, &self.name, optional, &self.ty) } } @@ -390,7 +388,6 @@ impl From> for Ty { } } -#[derive(Debug)] struct Enum { name: Name, members: Vec, @@ -414,6 +411,16 @@ impl From for Enum { } } +impl Debug for Enum { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut tup = f.debug_tuple(&self.name.0); + for member in &self.members { + tup.field(member); + } + tup.finish() + } +} + fn member_name(id: &TsEnumMemberId) -> Name { match id { TsEnumMemberId::Ident(i) => &i.sym, From 2ba1083f9f1d23bd2a0b1226f98c8fc7d338f6b5 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 11:55:26 -0700 Subject: [PATCH 09/41] [ts-bindgen] handle async/generator functions --- dom/ts-bindgen/src/typescript.rs | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 182cbdd24..3669a6933 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -290,6 +290,8 @@ impl Debug for Class { } struct Func { + is_generator: bool, + is_async: bool, params: Vec, returns: Option, } @@ -297,6 +299,8 @@ struct Func { impl Func { fn ctor(class: &Class, params: Vec) -> Self { Self { + is_async: false, + is_generator: false, params: params .into_iter() .map(|param| match param { @@ -313,16 +317,25 @@ impl Func { impl From for Func { fn from(function: Function) -> Self { - Self { params: function.params.into_iter().map(From::from).collect(), returns: None } + Self { + is_async: function.is_async, + is_generator: function.is_generator, + params: function.params.into_iter().map(From::from).collect(), + returns: function.return_type.map(From::from), + } } } impl Debug for Func { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let asyncness = if self.is_async { "async " } else { "" }; + let genny = if self.is_generator { "*" } else { "" }; + let prelude = format!("{}function{} ", asyncness, genny); + if self.params.is_empty() { - write!(f, "()")?; + write!(f, "{}()", prelude)?; } else { - let mut tup = f.debug_tuple(""); + let mut tup = f.debug_tuple(&prelude); for p in &self.params { tup.field(p); } @@ -378,13 +391,15 @@ impl From for Ty { } } +impl From for Ty { + fn from(ann: TsTypeAnn) -> Ty { + (*ann.type_ann).into() + } +} + impl From> for Ty { fn from(ann: Option) -> Ty { - if let Some(ann) = ann { - (*ann.type_ann).into() - } else { - Ty {} // TODO make an Any/universal type i guess? - } + ann.map(From::from).unwrap_or(Ty {}) // TODO make an Any/universal type i guess? } } From 3d387b8171084b902823cccc8db046586520c2b1 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 13:02:33 -0700 Subject: [PATCH 10/41] [ts-bindgen] modules have functions --- dom/ts-bindgen/src/typescript.rs | 37 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 3669a6933..e5c9fdcc0 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -48,13 +48,14 @@ impl Display for Name { pub struct TsModule { enums: Vec, classes: Vec, + functions: BTreeMap, children: BTreeMap, } impl Debug for TsModule { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list().entries(&self.enums).entries(&self.classes).finish()?; - f.debug_map().entries(&self.children).finish() + f.debug_map().entries(&self.functions).entries(&self.children).finish() } } @@ -80,6 +81,7 @@ impl TsModule { children: Default::default(), classes: Default::default(), enums: Default::default(), + functions: Default::default(), } } @@ -175,8 +177,9 @@ impl TsModule { } } - fn add_function(&mut self, _fun: FnDecl) { - println!("TODO functions"); + fn add_function(&mut self, fun: FnDecl) { + let name = Name::from(fun.ident.sym.to_string()); + self.functions.insert(name, fun.function.into()); } fn add_class(&mut self, class: ClassDecl) { @@ -211,7 +214,6 @@ impl TsModule { } struct Class { - name: Name, constructors: Vec, statics: BTreeMap, methods: BTreeMap, @@ -220,7 +222,6 @@ struct Class { impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { - name: class.ident.sym.to_string().into(), constructors: Default::default(), statics: Default::default(), methods: Default::default(), @@ -275,16 +276,14 @@ impl Class { impl Debug for Class { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut f = f.debug_struct(&self.name.0); + let mut f = f.debug_map(); + let ctor_name = Name::from("constructor".to_string()); for ctor in &self.constructors { - f.field("constructor", &ctor); - } - - for (name, function) in &self.methods { - f.field(&name.0, function); + f.entry(&ctor_name, &ctor); } + f.entries(&self.methods); f.finish() } } @@ -358,12 +357,12 @@ impl From for TsParam { match param.pat { Pat::Ident(i) => { let name = i.sym.to_string().into(); - let ty = i.type_ann.into(); + let ty = i.type_ann.map(Ty::from).unwrap_or_else(Ty::any); Self { name, ty, rest: false, optional: i.optional } } Pat::Rest(r) => { let name = r.arg.expect_ident().sym.to_string().into(); - let ty = r.type_ann.into(); + let ty = r.type_ann.map(Ty::from).unwrap_or_else(Ty::any); Self { name, ty, rest: true, optional: false } } other => todo!("other parameter types like {:#?}", other), @@ -384,6 +383,12 @@ struct Ty { // TODO figure out a repr for not-yet-resolved types } +impl Ty { + fn any() -> Self { + Ty {} + } +} + impl From for Ty { fn from(_ty: TsType) -> Ty { // TODO ...stuff @@ -397,12 +402,6 @@ impl From for Ty { } } -impl From> for Ty { - fn from(ann: Option) -> Ty { - ann.map(From::from).unwrap_or(Ty {}) // TODO make an Any/universal type i guess? - } -} - struct Enum { name: Name, members: Vec, From 5b09cacc1e337710f522bf28cfa57ae4045d9895 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 13:33:38 -0700 Subject: [PATCH 11/41] [ts-bindgen] start splitting typescript into submodules, starting with Ty --- dom/ts-bindgen/src/typescript.rs | 29 ++------ dom/ts-bindgen/src/typescript/ty.rs | 105 ++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 25 deletions(-) create mode 100644 dom/ts-bindgen/src/typescript/ty.rs diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index e5c9fdcc0..490339cbb 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -8,6 +8,9 @@ use swc_common::BytePos; use swc_ecma_ast::*; use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; +mod ty; +use ty::Ty; + pub fn parse_d_ts(contents: &str) -> Result { let input = StringInput::new(contents, BytePos(0), BytePos(0)); let mut parser = Parser::new( @@ -378,30 +381,6 @@ impl Debug for TsParam { } } -#[derive(Debug)] -struct Ty { - // TODO figure out a repr for not-yet-resolved types -} - -impl Ty { - fn any() -> Self { - Ty {} - } -} - -impl From for Ty { - fn from(_ty: TsType) -> Ty { - // TODO ...stuff - Ty {} - } -} - -impl From for Ty { - fn from(ann: TsTypeAnn) -> Ty { - (*ann.type_ann).into() - } -} - struct Enum { name: Name, members: Vec, @@ -464,6 +443,6 @@ fn prop_name(key: PropName) -> Name { impl TsModule { pub fn import_with_wasm_bindgen(&self) -> Result { - todo!("{:#?}", self) + todo!("{:?}", self) } } diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs new file mode 100644 index 000000000..2c47cf0a6 --- /dev/null +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -0,0 +1,105 @@ +use swc_ecma_ast::*; + +#[derive(Debug)] +pub struct Ty { + // TODO figure out a better repr for not-yet-resolved types +} + +impl Ty { + pub fn any() -> Self { + Ty {} + } +} + +impl From for Ty { + fn from(ty: TsType) -> Ty { + match ty { + TsType::TsKeywordType(kw) => { + println!("TODO keyword types"); + Ty::any() + } + TsType::TsThisType(_) => { + println!("TODO handle `this` in type annotation??"); + Ty::any() + } + TsType::TsFnOrConstructorType(_) => { + println!("TODO function or ctor type in annotation"); + Ty::any() + } + TsType::TsTypeRef(r) => { + println!("TODO type reference in annotations"); + Ty::any() + } + TsType::TsTypeQuery(q) => { + println!("TODO type queries in annotations"); + Ty::any() + } + TsType::TsTypeLit(l) => { + println!("TODO type literals in annotations"); + Ty::any() + } + TsType::TsArrayType(a) => { + println!("TODO array types in annotations"); + Ty::any() + } + TsType::TsTupleType(t) => { + println!("TODO tuple types in annotations"); + Ty::any() + } + TsType::TsOptionalType(o) => { + println!("TODO optional types in annotations"); + Ty::any() + } + TsType::TsRestType(r) => { + println!("TODO rest types in annotations"); + Ty::any() + } + TsType::TsUnionOrIntersectionType(u) => { + println!("TODO union/intersect types in annotations"); + Ty::any() + } + TsType::TsConditionalType(c) => { + println!("TODO conditional types in annotations"); + Ty::any() + } + TsType::TsInferType(i) => { + println!("TODO inferred types in annotations"); + Ty::any() + } + TsType::TsParenthesizedType(p) => { + println!("TODO paren'sized types in annotations"); + Ty::any() + } + TsType::TsTypeOperator(o) => { + println!("TODO type operators in annotations"); + Ty::any() + } + TsType::TsIndexedAccessType(i) => { + println!("TODO indexed access types in annotations"); + Ty::any() + } + TsType::TsMappedType(m) => { + println!("TODO mapped types in annotations"); + Ty::any() + } + TsType::TsLitType(l) => { + println!("TODO literal types in annotations"); + Ty::any() + } + TsType::TsTypePredicate(p) => { + println!("TODO predicates in annotations"); + Ty::any() + } + TsType::TsImportType(i) => { + println!("TODO import types in annotations"); + Ty::any() + } + } + } +} + +impl From for Ty { + fn from(ann: TsTypeAnn) -> Ty { + (*ann.type_ann).into() + } +} From 2c87f79ecf2a6c66e2695324f4ed2419555b608c Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 13:48:44 -0700 Subject: [PATCH 12/41] [ts-bindgen] finish splitting typescript.rs up --- dom/ts-bindgen/src/typescript.rs | 436 +----------------------- dom/ts-bindgen/src/typescript/class.rs | 91 +++++ dom/ts-bindgen/src/typescript/enums.rs | 46 +++ dom/ts-bindgen/src/typescript/func.rs | 61 ++++ dom/ts-bindgen/src/typescript/module.rs | 181 ++++++++++ dom/ts-bindgen/src/typescript/name.rs | 28 ++ dom/ts-bindgen/src/typescript/param.rs | 37 ++ 7 files changed, 460 insertions(+), 420 deletions(-) create mode 100644 dom/ts-bindgen/src/typescript/class.rs create mode 100644 dom/ts-bindgen/src/typescript/enums.rs create mode 100644 dom/ts-bindgen/src/typescript/func.rs create mode 100644 dom/ts-bindgen/src/typescript/module.rs create mode 100644 dom/ts-bindgen/src/typescript/name.rs create mode 100644 dom/ts-bindgen/src/typescript/param.rs diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 490339cbb..d2e8f30e4 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -1,15 +1,23 @@ -use crate::{error::TypescriptError, wasm::WasmBindgenImport}; -use std::{ - collections::BTreeMap, - fmt::{Debug, Display, Formatter, Result as FmtResult}, - str::FromStr, -}; +use crate::error::TypescriptError; use swc_common::BytePos; use swc_ecma_ast::*; use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; +mod class; +mod enums; +mod func; +mod module; +mod name; +mod param; mod ty; -use ty::Ty; + +pub use class::Class; +pub use enums::Enum; +pub use func::Func; +pub use module::TsModule; +pub use name::Name; +pub use param::TsParam; +pub use ty::Ty; pub fn parse_d_ts(contents: &str) -> Result { let input = StringInput::new(contents, BytePos(0), BytePos(0)); @@ -27,422 +35,10 @@ pub fn parse_d_ts(contents: &str) -> Result { Ok(parser.parse_typescript_module()?) } -#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] -struct Name(String); - -impl From for Name { - fn from(s: String) -> Self { - Name(s.to_string()) - } -} - -impl Debug for Name { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(&self.0) - } -} - -impl Display for Name { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(&self.0) - } -} - -pub struct TsModule { - enums: Vec, - classes: Vec, - functions: BTreeMap, - children: BTreeMap, -} - -impl Debug for TsModule { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_list().entries(&self.enums).entries(&self.classes).finish()?; - f.debug_map().entries(&self.functions).entries(&self.children).finish() - } -} - -impl FromStr for TsModule { +impl std::str::FromStr for module::TsModule { type Err = TypescriptError; fn from_str(s: &str) -> Result { Ok(Self::from(parse_d_ts(s)?)) } } - -impl From for TsModule { - fn from(module: Module) -> Self { - let mut new = TsModule::blank(); - new.add_module_contents(module.body); - new - } -} - -impl TsModule { - fn blank() -> Self { - Self { - children: Default::default(), - classes: Default::default(), - enums: Default::default(), - functions: Default::default(), - } - } - - fn add_module_contents(&mut self, contents: Vec) { - for item in contents { - match item { - ModuleItem::ModuleDecl(decl) => match decl { - ModuleDecl::Import(import) => self.add_import(import), - ModuleDecl::ExportDecl(export) => self.add_decl(export.decl), - ModuleDecl::ExportNamed(named) => self.add_named_export(named), - ModuleDecl::ExportDefaultDecl(default_decl) => { - self.add_default_export(default_decl) - } - ModuleDecl::ExportDefaultExpr(expr) => self.add_default_export_expr(expr), - ModuleDecl::ExportAll(export_all) => self.add_export_all(export_all), - - ModuleDecl::TsImportEquals(ts_import) => self.add_import_equals(ts_import), - ModuleDecl::TsExportAssignment(ts_export) => self.add_export_assign(ts_export), - ModuleDecl::TsNamespaceExport(ts_ns_export) => { - self.add_namespace_export(ts_ns_export) - } - }, - ModuleItem::Stmt(stmt) => self.add_stmt(stmt), - } - } - } - - fn add_import(&mut self, _import: ImportDecl) { - println!("TODO support imports"); - } - - pub fn add_named_export(&mut self, _named: NamedExport) { - println!("TODO support re-exports"); - } - - pub fn add_default_export(&mut self, _default_decl: ExportDefaultDecl) { - println!("TODO export default decl"); - } - - pub fn add_default_export_expr(&mut self, _default_expr: ExportDefaultExpr) { - println!("TODO export default expr"); - } - - pub fn add_export_all(&mut self, _export_all: ExportAll) { - println!("TODO export all"); - } - - pub fn add_import_equals(&mut self, _ts_import: TsImportEqualsDecl) { - println!("TODO ts import"); - } - - pub fn add_export_assign(&mut self, _ts_export: TsExportAssignment) { - println!("TODO export assignment"); - } - - pub fn add_namespace_export(&mut self, _ts_ns_export: TsNamespaceExportDecl) { - println!("TODO typescript namespace export"); - } - - fn add_stmt(&mut self, stmt: Stmt) { - match stmt { - Stmt::Decl(decl) => self.add_decl(decl), - _ => { - println!("TODO non-decl statements"); - } - } - } - - fn add_decl(&mut self, decl: Decl) { - match decl { - Decl::Class(class) => self.add_class(class), - Decl::TsInterface(interface) => self.add_interface(interface), - Decl::TsTypeAlias(alias) => self.add_alias(alias), - Decl::TsEnum(ts_enum) => self.add_enum(ts_enum), - Decl::TsModule(TsModuleDecl { id, body, .. }) => self.add_ts_module(id, body), - Decl::Fn(fun) => self.add_function(fun), - Decl::Var(var) => self.add_var(var), - } - } - - fn add_var(&mut self, var: VarDecl) { - for decl in var.decls { - let name = match decl.name { - Pat::Ident(n) => Name::from(n.sym.to_string()), - other => { - todo!("i guess implement support for assignments to {:?}", other); - } - }; - - if let Some(init) = decl.init { - todo!("i guess support initializing {:?} {:?} {:?}", &var.kind, name, init); - } - } - } - - fn add_function(&mut self, fun: FnDecl) { - let name = Name::from(fun.ident.sym.to_string()); - self.functions.insert(name, fun.function.into()); - } - - fn add_class(&mut self, class: ClassDecl) { - self.classes.push(class.into()); - } - - fn add_interface(&mut self, _interface: TsInterfaceDecl) { - println!("TODO interfaces"); - } - - fn add_alias(&mut self, _alias: TsTypeAliasDecl) { - println!("TODO ts aliases"); - } - - fn add_enum(&mut self, decl: TsEnumDecl) { - self.enums.push(decl.into()); - } - - fn add_ts_module(&mut self, id: TsModuleName, body: Option) { - let new_child = self.children.entry(module_name(&id)).or_insert_with(TsModule::blank); - - match body { - Some(TsNamespaceBody::TsModuleBlock(block)) => { - new_child.add_module_contents(block.body); - } - Some(TsNamespaceBody::TsNamespaceDecl(TsNamespaceDecl { id, body, .. })) => { - new_child.add_ts_module(TsModuleName::Ident(id), Some(*body)); - } - None => (), - } - } -} - -struct Class { - constructors: Vec, - statics: BTreeMap, - methods: BTreeMap, -} - -impl From for Class { - fn from(class: ClassDecl) -> Self { - let mut new = Class { - constructors: Default::default(), - statics: Default::default(), - methods: Default::default(), - }; - - // TODO type params - // TODO super class & type params - // TODO implemented interfaces - - for member in class.class.body { - match member { - ClassMember::Constructor(ctor) => new.add_constructor(ctor), - ClassMember::Method(method) => new.add_method(method), - ClassMember::ClassProp(_) => { - println!("TODO figure out if we care about class properties") - } - ClassMember::PrivateMethod(_) => { - println!("TODO figure out if we care about private methods") - } - ClassMember::PrivateProp(_) => { - println!("TODO figure out if we care about private properties") - } - ClassMember::TsIndexSignature(_) => println!("TODO figure out ts index signatures"), - ClassMember::Empty(_) => (), - } - } - - new - } -} - -impl Class { - fn ty(&self) -> Ty { - Ty {} // TODO return *this*'s type - } - - fn add_constructor(&mut self, ctor: Constructor) { - self.constructors.push(Func::ctor(&self, ctor.params)); - } - - fn add_method(&mut self, method: ClassMethod) { - let name = prop_name(method.key); - let func = Func::from(method.function); - - if method.is_static { - self.statics.insert(name, func); - } else { - self.methods.insert(name, func); - } - } -} - -impl Debug for Class { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut f = f.debug_map(); - - let ctor_name = Name::from("constructor".to_string()); - for ctor in &self.constructors { - f.entry(&ctor_name, &ctor); - } - - f.entries(&self.methods); - f.finish() - } -} - -struct Func { - is_generator: bool, - is_async: bool, - params: Vec, - returns: Option, -} - -impl Func { - fn ctor(class: &Class, params: Vec) -> Self { - Self { - is_async: false, - is_generator: false, - params: params - .into_iter() - .map(|param| match param { - ParamOrTsParamProp::Param(p) => p.into(), - ParamOrTsParamProp::TsParamProp(t) => { - todo!("support ts 'param props' from swc ast {:#?}", t); - } - }) - .collect(), - returns: Some(class.ty()), - } - } -} - -impl From for Func { - fn from(function: Function) -> Self { - Self { - is_async: function.is_async, - is_generator: function.is_generator, - params: function.params.into_iter().map(From::from).collect(), - returns: function.return_type.map(From::from), - } - } -} - -impl Debug for Func { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let asyncness = if self.is_async { "async " } else { "" }; - let genny = if self.is_generator { "*" } else { "" }; - let prelude = format!("{}function{} ", asyncness, genny); - - if self.params.is_empty() { - write!(f, "{}()", prelude)?; - } else { - let mut tup = f.debug_tuple(&prelude); - for p in &self.params { - tup.field(p); - } - tup.finish()?; - } - - if let Some(ret) = &self.returns { write!(f, " -> {:?}", ret) } else { Ok(()) } - } -} - -struct TsParam { - name: Name, - optional: bool, - rest: bool, - ty: Ty, -} - -impl From for TsParam { - fn from(param: Param) -> TsParam { - match param.pat { - Pat::Ident(i) => { - let name = i.sym.to_string().into(); - let ty = i.type_ann.map(Ty::from).unwrap_or_else(Ty::any); - Self { name, ty, rest: false, optional: i.optional } - } - Pat::Rest(r) => { - let name = r.arg.expect_ident().sym.to_string().into(); - let ty = r.type_ann.map(Ty::from).unwrap_or_else(Ty::any); - Self { name, ty, rest: true, optional: false } - } - other => todo!("other parameter types like {:#?}", other), - } - } -} - -impl Debug for TsParam { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let rest = if self.rest { "..." } else { "" }; - let optional = if self.optional { "?" } else { "" }; - write!(f, "{}{}{}: {:?}", rest, &self.name, optional, &self.ty) - } -} - -struct Enum { - name: Name, - members: Vec, -} - -impl From for Enum { - fn from(decl: TsEnumDecl) -> Self { - let name = decl.id.sym.to_string().into(); - let members = decl - .members - .into_iter() - .map(|member| { - let member_name = member_name(&member.id); - if member.init.is_some() { - println!("TODO enum member init {:?}.{:?}", &name, &member_name); - } - member_name - }) - .collect(); - Enum { name, members } - } -} - -impl Debug for Enum { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut tup = f.debug_tuple(&self.name.0); - for member in &self.members { - tup.field(member); - } - tup.finish() - } -} - -fn member_name(id: &TsEnumMemberId) -> Name { - match id { - TsEnumMemberId::Ident(i) => &i.sym, - TsEnumMemberId::Str(s) => &s.value, - } - .to_string() - .into() -} - -fn module_name(id: &TsModuleName) -> Name { - match id { - TsModuleName::Ident(i) => &i.sym, - TsModuleName::Str(s) => &s.value, - } - .to_string() - .into() -} - -fn prop_name(key: PropName) -> Name { - match key { - PropName::Ident(i) => i.sym.to_string().into(), - PropName::Str(s) => s.value.to_string().into(), - PropName::Num(n) => n.value.to_string().into(), - PropName::Computed(c) => todo!("support computed property names: {:#?}", c), - } -} - -impl TsModule { - pub fn import_with_wasm_bindgen(&self) -> Result { - todo!("{:?}", self) - } -} diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs new file mode 100644 index 000000000..a0a3e610a --- /dev/null +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -0,0 +1,91 @@ +use std::{ + collections::BTreeMap, + fmt::{Debug, Formatter, Result as FmtResult}, +}; +use swc_ecma_ast::*; + +use super::{Func, Name, Ty}; + +pub struct Class { + constructors: Vec, + statics: BTreeMap, + methods: BTreeMap, +} + +impl From for Class { + fn from(class: ClassDecl) -> Self { + let mut new = Class { + constructors: Default::default(), + statics: Default::default(), + methods: Default::default(), + }; + + // TODO type params + // TODO super class & type params + // TODO implemented interfaces + + for member in class.class.body { + match member { + ClassMember::Constructor(ctor) => new.add_constructor(ctor), + ClassMember::Method(method) => new.add_method(method), + ClassMember::ClassProp(_) => { + println!("TODO figure out if we care about class properties") + } + ClassMember::PrivateMethod(_) => { + println!("TODO figure out if we care about private methods") + } + ClassMember::PrivateProp(_) => { + println!("TODO figure out if we care about private properties") + } + ClassMember::TsIndexSignature(_) => println!("TODO figure out ts index signatures"), + ClassMember::Empty(_) => (), + } + } + + new + } +} + +impl Class { + pub fn ty(&self) -> Ty { + Ty {} // TODO return *this*'s type + } + + fn add_constructor(&mut self, ctor: Constructor) { + self.constructors.push(Func::ctor(&self, ctor.params)); + } + + fn add_method(&mut self, method: ClassMethod) { + let name = prop_name(method.key); + let func = Func::from(method.function); + + if method.is_static { + self.statics.insert(name, func); + } else { + self.methods.insert(name, func); + } + } +} + +impl Debug for Class { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut f = f.debug_map(); + + let ctor_name = Name::from("constructor".to_string()); + for ctor in &self.constructors { + f.entry(&ctor_name, &ctor); + } + + f.entries(&self.methods); + f.finish() + } +} + +fn prop_name(key: PropName) -> Name { + match key { + PropName::Ident(i) => i.sym.to_string().into(), + PropName::Str(s) => s.value.to_string().into(), + PropName::Num(n) => n.value.to_string().into(), + PropName::Computed(c) => todo!("support computed property names: {:#?}", c), + } +} diff --git a/dom/ts-bindgen/src/typescript/enums.rs b/dom/ts-bindgen/src/typescript/enums.rs new file mode 100644 index 000000000..8bd997006 --- /dev/null +++ b/dom/ts-bindgen/src/typescript/enums.rs @@ -0,0 +1,46 @@ +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use swc_ecma_ast::*; + +use super::Name; + +pub struct Enum { + name: Name, + members: Vec, +} + +impl From for Enum { + fn from(decl: TsEnumDecl) -> Self { + let name = decl.id.sym.to_string().into(); + let members = decl + .members + .into_iter() + .map(|member| { + let member_name = member_name(&member.id); + if member.init.is_some() { + println!("TODO enum member init {:?}.{:?}", &name, &member_name); + } + member_name + }) + .collect(); + Enum { name, members } + } +} + +impl Debug for Enum { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut tup = f.debug_tuple(&self.name.as_ref()); + for member in &self.members { + tup.field(member); + } + tup.finish() + } +} + +fn member_name(id: &TsEnumMemberId) -> Name { + match id { + TsEnumMemberId::Ident(i) => &i.sym, + TsEnumMemberId::Str(s) => &s.value, + } + .to_string() + .into() +} diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs new file mode 100644 index 000000000..779b93185 --- /dev/null +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -0,0 +1,61 @@ +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use swc_ecma_ast::*; + +use super::{Class, TsParam, Ty}; + +pub struct Func { + is_generator: bool, + is_async: bool, + params: Vec, + returns: Option, +} + +impl Func { + pub fn ctor(class: &Class, params: Vec) -> Self { + Self { + is_async: false, + is_generator: false, + params: params + .into_iter() + .map(|param| match param { + ParamOrTsParamProp::Param(p) => p.into(), + ParamOrTsParamProp::TsParamProp(t) => { + todo!("support ts 'param props' from swc ast {:#?}", t); + } + }) + .collect(), + returns: Some(class.ty()), + } + } +} + +impl From for Func { + fn from(function: Function) -> Self { + Self { + is_async: function.is_async, + is_generator: function.is_generator, + params: function.params.into_iter().map(From::from).collect(), + returns: function.return_type.map(From::from), + } + } +} + +impl Debug for Func { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let asyncness = if self.is_async { "async " } else { "" }; + let genny = if self.is_generator { "*" } else { "" }; + let prelude = format!("{}function{} ", asyncness, genny); + + if self.params.is_empty() { + write!(f, "{}()", prelude)?; + } else { + let mut tup = f.debug_tuple(&prelude); + for p in &self.params { + tup.field(p); + } + tup.finish()?; + } + + if let Some(ret) = &self.returns { write!(f, " -> {:?}", ret) } else { Ok(()) } + } +} diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs new file mode 100644 index 000000000..a44fa8115 --- /dev/null +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -0,0 +1,181 @@ +use crate::{error::TypescriptError, wasm::WasmBindgenImport}; +use std::{ + collections::BTreeMap, + fmt::{Debug, Formatter, Result as FmtResult}, +}; +use swc_ecma_ast::*; + +use super::{class::Class, enums::Enum, func::Func, name::Name}; + +pub struct TsModule { + enums: Vec, + classes: Vec, + functions: BTreeMap, + children: BTreeMap, +} + +impl Debug for TsModule { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.debug_list().entries(&self.enums).entries(&self.classes).finish()?; + f.debug_map().entries(&self.functions).entries(&self.children).finish() + } +} + +impl From for TsModule { + fn from(module: Module) -> Self { + let mut new = TsModule::blank(); + new.add_module_contents(module.body); + new + } +} + +impl TsModule { + fn blank() -> Self { + Self { + children: Default::default(), + classes: Default::default(), + enums: Default::default(), + functions: Default::default(), + } + } + + fn add_module_contents(&mut self, contents: Vec) { + for item in contents { + match item { + ModuleItem::ModuleDecl(decl) => match decl { + ModuleDecl::Import(import) => self.add_import(import), + ModuleDecl::ExportDecl(export) => self.add_decl(export.decl), + ModuleDecl::ExportNamed(named) => self.add_named_export(named), + ModuleDecl::ExportDefaultDecl(default_decl) => { + self.add_default_export(default_decl) + } + ModuleDecl::ExportDefaultExpr(expr) => self.add_default_export_expr(expr), + ModuleDecl::ExportAll(export_all) => self.add_export_all(export_all), + + ModuleDecl::TsImportEquals(ts_import) => self.add_import_equals(ts_import), + ModuleDecl::TsExportAssignment(ts_export) => self.add_export_assign(ts_export), + ModuleDecl::TsNamespaceExport(ts_ns_export) => { + self.add_namespace_export(ts_ns_export) + } + }, + ModuleItem::Stmt(stmt) => self.add_stmt(stmt), + } + } + } + + fn add_import(&mut self, _import: ImportDecl) { + println!("TODO support imports"); + } + + pub fn add_named_export(&mut self, _named: NamedExport) { + println!("TODO support re-exports"); + } + + pub fn add_default_export(&mut self, _default_decl: ExportDefaultDecl) { + println!("TODO export default decl"); + } + + pub fn add_default_export_expr(&mut self, _default_expr: ExportDefaultExpr) { + println!("TODO export default expr"); + } + + pub fn add_export_all(&mut self, _export_all: ExportAll) { + println!("TODO export all"); + } + + pub fn add_import_equals(&mut self, _ts_import: TsImportEqualsDecl) { + println!("TODO ts import"); + } + + pub fn add_export_assign(&mut self, _ts_export: TsExportAssignment) { + println!("TODO export assignment"); + } + + pub fn add_namespace_export(&mut self, _ts_ns_export: TsNamespaceExportDecl) { + println!("TODO typescript namespace export"); + } + + fn add_stmt(&mut self, stmt: Stmt) { + match stmt { + Stmt::Decl(decl) => self.add_decl(decl), + _ => { + println!("TODO non-decl statements"); + } + } + } + + fn add_decl(&mut self, decl: Decl) { + match decl { + Decl::Class(class) => self.add_class(class), + Decl::TsInterface(interface) => self.add_interface(interface), + Decl::TsTypeAlias(alias) => self.add_alias(alias), + Decl::TsEnum(ts_enum) => self.add_enum(ts_enum), + Decl::TsModule(TsModuleDecl { id, body, .. }) => self.add_ts_module(id, body), + Decl::Fn(fun) => self.add_function(fun), + Decl::Var(var) => self.add_var(var), + } + } + + fn add_var(&mut self, var: VarDecl) { + for decl in var.decls { + let name = match decl.name { + Pat::Ident(n) => Name::from(n.sym.to_string()), + other => { + todo!("i guess implement support for assignments to {:?}", other); + } + }; + + if let Some(init) = decl.init { + todo!("i guess support initializing {:?} {:?} {:?}", &var.kind, name, init); + } + } + } + + fn add_function(&mut self, fun: FnDecl) { + let name = Name::from(fun.ident.sym.to_string()); + self.functions.insert(name, fun.function.into()); + } + + fn add_class(&mut self, class: ClassDecl) { + self.classes.push(class.into()); + } + + fn add_interface(&mut self, _interface: TsInterfaceDecl) { + println!("TODO interfaces"); + } + + fn add_alias(&mut self, _alias: TsTypeAliasDecl) { + println!("TODO ts aliases"); + } + + fn add_enum(&mut self, decl: TsEnumDecl) { + self.enums.push(decl.into()); + } + + fn add_ts_module(&mut self, id: TsModuleName, body: Option) { + let new_child = self.children.entry(module_name(&id)).or_insert_with(TsModule::blank); + + match body { + Some(TsNamespaceBody::TsModuleBlock(block)) => { + new_child.add_module_contents(block.body); + } + Some(TsNamespaceBody::TsNamespaceDecl(TsNamespaceDecl { id, body, .. })) => { + new_child.add_ts_module(TsModuleName::Ident(id), Some(*body)); + } + None => (), + } + } + + pub fn import_with_wasm_bindgen(&self) -> Result { + todo!("{:?}", self) + } +} + +fn module_name(id: &TsModuleName) -> Name { + match id { + TsModuleName::Ident(i) => &i.sym, + TsModuleName::Str(s) => &s.value, + } + .to_string() + .into() +} diff --git a/dom/ts-bindgen/src/typescript/name.rs b/dom/ts-bindgen/src/typescript/name.rs new file mode 100644 index 000000000..cac378182 --- /dev/null +++ b/dom/ts-bindgen/src/typescript/name.rs @@ -0,0 +1,28 @@ +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; + +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct Name(String); + +impl From for Name { + fn from(s: String) -> Self { + Name(s.to_string()) + } +} + +impl AsRef for Name { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl Debug for Name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(&self.0) + } +} + +impl Display for Name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(&self.0) + } +} diff --git a/dom/ts-bindgen/src/typescript/param.rs b/dom/ts-bindgen/src/typescript/param.rs new file mode 100644 index 000000000..0375e8bab --- /dev/null +++ b/dom/ts-bindgen/src/typescript/param.rs @@ -0,0 +1,37 @@ +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use swc_ecma_ast::*; + +use super::{name::Name, ty::Ty}; + +pub struct TsParam { + name: Name, + optional: bool, + rest: bool, + ty: Ty, +} + +impl From for TsParam { + fn from(param: Param) -> TsParam { + match param.pat { + Pat::Ident(i) => { + let name = i.sym.to_string().into(); + let ty = i.type_ann.map(Ty::from).unwrap_or_else(Ty::any); + Self { name, ty, rest: false, optional: i.optional } + } + Pat::Rest(r) => { + let name = r.arg.expect_ident().sym.to_string().into(); + let ty = r.type_ann.map(Ty::from).unwrap_or_else(Ty::any); + Self { name, ty, rest: true, optional: false } + } + other => todo!("other parameter types like {:#?}", other), + } + } +} + +impl Debug for TsParam { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let rest = if self.rest { "..." } else { "" }; + let optional = if self.optional { "?" } else { "" }; + write!(f, "{}{}{}: {:?}", rest, &self.name, optional, &self.ty) + } +} From 2abba3054f6e4cb18e8a4f4f92233a9e28842a93 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 13:52:34 -0700 Subject: [PATCH 13/41] [ts-bindgen] start distinguishing between mvp and future work (basically what's needed for code-sys to work vs what's not) --- dom/ts-bindgen/src/typescript/class.rs | 14 ++++---------- dom/ts-bindgen/src/typescript/module.rs | 18 +++++++++--------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index a0a3e610a..f5065e199 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -28,16 +28,10 @@ impl From for Class { match member { ClassMember::Constructor(ctor) => new.add_constructor(ctor), ClassMember::Method(method) => new.add_method(method), - ClassMember::ClassProp(_) => { - println!("TODO figure out if we care about class properties") - } - ClassMember::PrivateMethod(_) => { - println!("TODO figure out if we care about private methods") - } - ClassMember::PrivateProp(_) => { - println!("TODO figure out if we care about private properties") - } - ClassMember::TsIndexSignature(_) => println!("TODO figure out ts index signatures"), + ClassMember::ClassProp(_) => println!("TODO class properties?"), + ClassMember::PrivateMethod(_) => todo!("private methods"), + ClassMember::PrivateProp(_) => todo!("private properties"), + ClassMember::TsIndexSignature(_) => todo!("ts index signatures"), ClassMember::Empty(_) => (), } } diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index a44fa8115..af91dbeda 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -64,42 +64,42 @@ impl TsModule { } fn add_import(&mut self, _import: ImportDecl) { - println!("TODO support imports"); + todo!("support imports"); } pub fn add_named_export(&mut self, _named: NamedExport) { - println!("TODO support re-exports"); + todo!("support re-exports"); } pub fn add_default_export(&mut self, _default_decl: ExportDefaultDecl) { - println!("TODO export default decl"); + todo!("export default decl"); } pub fn add_default_export_expr(&mut self, _default_expr: ExportDefaultExpr) { - println!("TODO export default expr"); + todo!("export default expr"); } pub fn add_export_all(&mut self, _export_all: ExportAll) { - println!("TODO export all"); + todo!("export all"); } pub fn add_import_equals(&mut self, _ts_import: TsImportEqualsDecl) { - println!("TODO ts import"); + todo!("ts import"); } pub fn add_export_assign(&mut self, _ts_export: TsExportAssignment) { - println!("TODO export assignment"); + todo!("export assignment"); } pub fn add_namespace_export(&mut self, _ts_ns_export: TsNamespaceExportDecl) { - println!("TODO typescript namespace export"); + todo!("typescript namespace export"); } fn add_stmt(&mut self, stmt: Stmt) { match stmt { Stmt::Decl(decl) => self.add_decl(decl), _ => { - println!("TODO non-decl statements"); + todo!("non-decl statements"); } } } From 9e4a16376a26378661c300ad7e0de09033a6e7f7 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 14:27:50 -0700 Subject: [PATCH 14/41] [ts-bindgen] remove glob imports from ast crate --- dom/ts-bindgen/src/typescript.rs | 2 +- dom/ts-bindgen/src/typescript/class.rs | 8 +++++--- dom/ts-bindgen/src/typescript/enums.rs | 2 +- dom/ts-bindgen/src/typescript/func.rs | 4 ++-- dom/ts-bindgen/src/typescript/module.rs | 7 ++++++- dom/ts-bindgen/src/typescript/param.rs | 2 +- dom/ts-bindgen/src/typescript/ty.rs | 6 ++++-- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index d2e8f30e4..05acc5cac 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -1,6 +1,6 @@ use crate::error::TypescriptError; use swc_common::BytePos; -use swc_ecma_ast::*; +use swc_ecma_ast::Module; use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; mod class; diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index f5065e199..df0f64f96 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -2,11 +2,12 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::*; +use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, Constructor, PropName}; use super::{Func, Name, Ty}; pub struct Class { + ty: Ty, constructors: Vec, statics: BTreeMap, methods: BTreeMap, @@ -15,6 +16,7 @@ pub struct Class { impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { + ty: Ty::any(), // TODO a real type? constructors: Default::default(), statics: Default::default(), methods: Default::default(), @@ -41,8 +43,8 @@ impl From for Class { } impl Class { - pub fn ty(&self) -> Ty { - Ty {} // TODO return *this*'s type + pub fn ty(&self) -> &Ty { + &self.ty } fn add_constructor(&mut self, ctor: Constructor) { diff --git a/dom/ts-bindgen/src/typescript/enums.rs b/dom/ts-bindgen/src/typescript/enums.rs index 8bd997006..da68067b4 100644 --- a/dom/ts-bindgen/src/typescript/enums.rs +++ b/dom/ts-bindgen/src/typescript/enums.rs @@ -1,5 +1,5 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::*; +use swc_ecma_ast::{TsEnumDecl, TsEnumMemberId}; use super::Name; diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index 779b93185..e524b7661 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -1,5 +1,5 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::*; +use swc_ecma_ast::{Function, ParamOrTsParamProp}; use super::{Class, TsParam, Ty}; @@ -24,7 +24,7 @@ impl Func { } }) .collect(), - returns: Some(class.ty()), + returns: Some(class.ty().clone()), } } } diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index af91dbeda..76c06742b 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -3,7 +3,12 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::*; +use swc_ecma_ast::{ + ClassDecl, Decl, ExportAll, ExportDefaultDecl, ExportDefaultExpr, FnDecl, ImportDecl, Module, + ModuleDecl, ModuleItem, NamedExport, Pat, Stmt, TsEnumDecl, TsExportAssignment, + TsImportEqualsDecl, TsInterfaceDecl, TsModuleDecl, TsModuleName, TsNamespaceBody, + TsNamespaceDecl, TsNamespaceExportDecl, TsTypeAliasDecl, VarDecl, +}; use super::{class::Class, enums::Enum, func::Func, name::Name}; diff --git a/dom/ts-bindgen/src/typescript/param.rs b/dom/ts-bindgen/src/typescript/param.rs index 0375e8bab..bd79a2a83 100644 --- a/dom/ts-bindgen/src/typescript/param.rs +++ b/dom/ts-bindgen/src/typescript/param.rs @@ -1,5 +1,5 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::*; +use swc_ecma_ast::{Param, Pat}; use super::{name::Name, ty::Ty}; diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 2c47cf0a6..5b1292a7f 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,6 +1,8 @@ -use swc_ecma_ast::*; +#![allow(unused)] -#[derive(Debug)] +use swc_ecma_ast::{TsType, TsTypeAnn}; + +#[derive(Clone, Debug)] pub struct Ty { // TODO figure out a better repr for not-yet-resolved types } From 660b23498ebe48fa2c7dff3f2f120c05c9f8533a Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 14:36:11 -0700 Subject: [PATCH 15/41] [ts-bindgen] finish variables in modules --- dom/ts-bindgen/src/typescript/module.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index 76c06742b..72b19c43d 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -10,9 +10,10 @@ use swc_ecma_ast::{ TsNamespaceDecl, TsNamespaceExportDecl, TsTypeAliasDecl, VarDecl, }; -use super::{class::Class, enums::Enum, func::Func, name::Name}; +use super::{class::Class, enums::Enum, func::Func, name::Name, ty::Ty}; pub struct TsModule { + variables: BTreeMap, enums: Vec, classes: Vec, functions: BTreeMap, @@ -22,7 +23,11 @@ pub struct TsModule { impl Debug for TsModule { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list().entries(&self.enums).entries(&self.classes).finish()?; - f.debug_map().entries(&self.functions).entries(&self.children).finish() + f.debug_map() + .entries(&self.variables) + .entries(&self.functions) + .entries(&self.children) + .finish() } } @@ -41,6 +46,7 @@ impl TsModule { classes: Default::default(), enums: Default::default(), functions: Default::default(), + variables: Default::default(), } } @@ -123,8 +129,11 @@ impl TsModule { fn add_var(&mut self, var: VarDecl) { for decl in var.decls { - let name = match decl.name { - Pat::Ident(n) => Name::from(n.sym.to_string()), + let (name, ty) = match decl.name { + Pat::Ident(n) => ( + Name::from(n.sym.to_string()), + n.type_ann.map(Ty::from).unwrap_or_else(Ty::any), + ), other => { todo!("i guess implement support for assignments to {:?}", other); } @@ -133,6 +142,8 @@ impl TsModule { if let Some(init) = decl.init { todo!("i guess support initializing {:?} {:?} {:?}", &var.kind, name, init); } + + self.variables.insert(name, ty); } } From fbd9393c4f05e46ad50790c882741f9566c37c54 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 14:45:34 -0700 Subject: [PATCH 16/41] [ts-bindgen] start adding interfaces in modules --- dom/ts-bindgen/src/typescript.rs | 2 ++ dom/ts-bindgen/src/typescript/class.rs | 12 ++++++---- dom/ts-bindgen/src/typescript/interface.rs | 28 ++++++++++++++++++++++ dom/ts-bindgen/src/typescript/module.rs | 14 +++++++---- 4 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 dom/ts-bindgen/src/typescript/interface.rs diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 05acc5cac..0d90b2d29 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -6,6 +6,7 @@ use swc_ecma_parser::{lexer::input::StringInput, Parser, Syntax, TsConfig}; mod class; mod enums; mod func; +mod interface; mod module; mod name; mod param; @@ -14,6 +15,7 @@ mod ty; pub use class::Class; pub use enums::Enum; pub use func::Func; +pub use interface::Interface; pub use module::TsModule; pub use name::Name; pub use param::TsParam; diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index df0f64f96..f21da95ab 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -7,6 +7,7 @@ use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, Constructor, PropName}; use super::{Func, Name, Ty}; pub struct Class { + name: Name, ty: Ty, constructors: Vec, statics: BTreeMap, @@ -17,6 +18,7 @@ impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { ty: Ty::any(), // TODO a real type? + name: class.ident.sym.to_string().into(), constructors: Default::default(), statics: Default::default(), methods: Default::default(), @@ -65,14 +67,16 @@ impl Class { impl Debug for Class { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut f = f.debug_map(); + let mut f = f.debug_struct(self.name.as_ref()); - let ctor_name = Name::from("constructor".to_string()); for ctor in &self.constructors { - f.entry(&ctor_name, &ctor); + f.field("constructor", &ctor); + } + + for (name, method) in &self.methods { + f.field(name.as_ref(), method); } - f.entries(&self.methods); f.finish() } } diff --git a/dom/ts-bindgen/src/typescript/interface.rs b/dom/ts-bindgen/src/typescript/interface.rs new file mode 100644 index 000000000..f02c584f6 --- /dev/null +++ b/dom/ts-bindgen/src/typescript/interface.rs @@ -0,0 +1,28 @@ +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use swc_ecma_ast::TsInterfaceDecl; + +use super::Name; + +pub struct Interface { + name: Name, +} + +impl From for Interface { + fn from(decl: TsInterfaceDecl) -> Self { + let name = Name::from(decl.id.sym.to_string()); + + // TODO + + Self { name } + } +} + +impl Debug for Interface { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut f = f.debug_struct(self.name.as_ref()); + + // TODO + + f.finish() + } +} diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index 72b19c43d..8785b9a7a 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -10,19 +10,24 @@ use swc_ecma_ast::{ TsNamespaceDecl, TsNamespaceExportDecl, TsTypeAliasDecl, VarDecl, }; -use super::{class::Class, enums::Enum, func::Func, name::Name, ty::Ty}; +use super::{class::Class, enums::Enum, func::Func, interface::Interface, name::Name, ty::Ty}; pub struct TsModule { variables: BTreeMap, enums: Vec, classes: Vec, + interfaces: Vec, functions: BTreeMap, children: BTreeMap, } impl Debug for TsModule { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_list().entries(&self.enums).entries(&self.classes).finish()?; + f.debug_list() + .entries(&self.enums) + .entries(&self.classes) + .entries(&self.interfaces) + .finish()?; f.debug_map() .entries(&self.variables) .entries(&self.functions) @@ -44,6 +49,7 @@ impl TsModule { Self { children: Default::default(), classes: Default::default(), + interfaces: Default::default(), enums: Default::default(), functions: Default::default(), variables: Default::default(), @@ -156,8 +162,8 @@ impl TsModule { self.classes.push(class.into()); } - fn add_interface(&mut self, _interface: TsInterfaceDecl) { - println!("TODO interfaces"); + fn add_interface(&mut self, interface: TsInterfaceDecl) { + self.interfaces.push(interface.into()); } fn add_alias(&mut self, _alias: TsTypeAliasDecl) { From 80f2084cdceedcdc0799facc4ed05d4edbd576e7 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 15:13:25 -0700 Subject: [PATCH 17/41] [ts-bindgen] move names into modules --- dom/ts-bindgen/src/typescript/class.rs | 21 +++++------- dom/ts-bindgen/src/typescript/enums.rs | 38 +++++++++------------- dom/ts-bindgen/src/typescript/interface.rs | 24 +++++--------- dom/ts-bindgen/src/typescript/module.rs | 18 +++++----- 4 files changed, 41 insertions(+), 60 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index f21da95ab..9386e048f 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -2,23 +2,21 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, Constructor, PropName}; +use swc_ecma_ast::{Class as AstClass, ClassMember, ClassMethod, Constructor, PropName}; use super::{Func, Name, Ty}; pub struct Class { - name: Name, ty: Ty, constructors: Vec, statics: BTreeMap, methods: BTreeMap, } -impl From for Class { - fn from(class: ClassDecl) -> Self { +impl From for Class { + fn from(class: AstClass) -> Self { let mut new = Class { ty: Ty::any(), // TODO a real type? - name: class.ident.sym.to_string().into(), constructors: Default::default(), statics: Default::default(), methods: Default::default(), @@ -28,7 +26,7 @@ impl From for Class { // TODO super class & type params // TODO implemented interfaces - for member in class.class.body { + for member in class.body { match member { ClassMember::Constructor(ctor) => new.add_constructor(ctor), ClassMember::Method(method) => new.add_method(method), @@ -67,16 +65,15 @@ impl Class { impl Debug for Class { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut f = f.debug_struct(self.name.as_ref()); + let mut f = f.debug_map(); + let ctor_name = Name::from("contructor".to_string()); for ctor in &self.constructors { - f.field("constructor", &ctor); - } - - for (name, method) in &self.methods { - f.field(name.as_ref(), method); + f.entry(&ctor_name, &ctor); } + f.entries(&self.statics); + f.entries(&self.methods); f.finish() } } diff --git a/dom/ts-bindgen/src/typescript/enums.rs b/dom/ts-bindgen/src/typescript/enums.rs index da68067b4..ffc173de4 100644 --- a/dom/ts-bindgen/src/typescript/enums.rs +++ b/dom/ts-bindgen/src/typescript/enums.rs @@ -1,38 +1,32 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::{TsEnumDecl, TsEnumMemberId}; +use swc_ecma_ast::{TsEnumMember, TsEnumMemberId}; use super::Name; pub struct Enum { - name: Name, members: Vec, } -impl From for Enum { - fn from(decl: TsEnumDecl) -> Self { - let name = decl.id.sym.to_string().into(); - let members = decl - .members - .into_iter() - .map(|member| { - let member_name = member_name(&member.id); - if member.init.is_some() { - println!("TODO enum member init {:?}.{:?}", &name, &member_name); - } - member_name - }) - .collect(); - Enum { name, members } +impl From> for Enum { + fn from(decls: Vec) -> Self { + Enum { + members: decls + .into_iter() + .map(|member| { + let member_name = member_name(&member.id); + if member.init.is_some() { + println!("TODO enum member init {:?}", &member_name); + } + member_name + }) + .collect(), + } } } impl Debug for Enum { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut tup = f.debug_tuple(&self.name.as_ref()); - for member in &self.members { - tup.field(member); - } - tup.finish() + f.debug_set().entries(&self.members).finish() } } diff --git a/dom/ts-bindgen/src/typescript/interface.rs b/dom/ts-bindgen/src/typescript/interface.rs index f02c584f6..e0d47d5d9 100644 --- a/dom/ts-bindgen/src/typescript/interface.rs +++ b/dom/ts-bindgen/src/typescript/interface.rs @@ -1,28 +1,20 @@ -use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::TsInterfaceDecl; - -use super::Name; +#![allow(unused)] -pub struct Interface { - name: Name, -} +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use swc_ecma_ast::TsInterfaceBody; -impl From for Interface { - fn from(decl: TsInterfaceDecl) -> Self { - let name = Name::from(decl.id.sym.to_string()); +pub struct Interface {} +impl From for Interface { + fn from(decl: TsInterfaceBody) -> Self { // TODO - Self { name } + Self {} } } impl Debug for Interface { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let mut f = f.debug_struct(self.name.as_ref()); - - // TODO - - f.finish() + Ok(()) } } diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index 8785b9a7a..e2b94cc8a 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -14,22 +14,20 @@ use super::{class::Class, enums::Enum, func::Func, interface::Interface, name::N pub struct TsModule { variables: BTreeMap, - enums: Vec, - classes: Vec, - interfaces: Vec, + enums: BTreeMap, + classes: BTreeMap, + interfaces: BTreeMap, functions: BTreeMap, children: BTreeMap, } impl Debug for TsModule { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_list() + f.debug_map() + .entries(&self.variables) .entries(&self.enums) .entries(&self.classes) .entries(&self.interfaces) - .finish()?; - f.debug_map() - .entries(&self.variables) .entries(&self.functions) .entries(&self.children) .finish() @@ -159,11 +157,11 @@ impl TsModule { } fn add_class(&mut self, class: ClassDecl) { - self.classes.push(class.into()); + self.classes.insert(class.ident.sym.to_string().into(), class.class.into()); } fn add_interface(&mut self, interface: TsInterfaceDecl) { - self.interfaces.push(interface.into()); + self.interfaces.insert(Name::from(interface.id.sym.to_string()), interface.body.into()); } fn add_alias(&mut self, _alias: TsTypeAliasDecl) { @@ -171,7 +169,7 @@ impl TsModule { } fn add_enum(&mut self, decl: TsEnumDecl) { - self.enums.push(decl.into()); + self.enums.insert(decl.id.sym.to_string().into(), decl.members.into()); } fn add_ts_module(&mut self, id: TsModuleName, body: Option) { From 89d007ad8fb363c380838eb5676d4a36fac1e2fa Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 15:17:42 -0700 Subject: [PATCH 18/41] [ts-bindgen] aliases --- dom/ts-bindgen/src/typescript/module.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index e2b94cc8a..8884d1224 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -14,6 +14,7 @@ use super::{class::Class, enums::Enum, func::Func, interface::Interface, name::N pub struct TsModule { variables: BTreeMap, + aliases: BTreeMap, enums: BTreeMap, classes: BTreeMap, interfaces: BTreeMap, @@ -45,6 +46,7 @@ impl From for TsModule { impl TsModule { fn blank() -> Self { Self { + aliases: Default::default(), children: Default::default(), classes: Default::default(), interfaces: Default::default(), @@ -161,11 +163,11 @@ impl TsModule { } fn add_interface(&mut self, interface: TsInterfaceDecl) { - self.interfaces.insert(Name::from(interface.id.sym.to_string()), interface.body.into()); + self.interfaces.insert(interface.id.sym.to_string().into(), interface.body.into()); } - fn add_alias(&mut self, _alias: TsTypeAliasDecl) { - println!("TODO ts aliases"); + fn add_alias(&mut self, alias: TsTypeAliasDecl) { + self.aliases.insert(alias.id.sym.to_string().into(), From::from(*alias.type_ann)); } fn add_enum(&mut self, decl: TsEnumDecl) { From 13e3795c8fb93f8cd7cf6c461825d0a51f34e854 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 15:23:38 -0700 Subject: [PATCH 19/41] [ts-bindgen] remove old todo --- dom/ts-bindgen/src/typescript/enums.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/enums.rs b/dom/ts-bindgen/src/typescript/enums.rs index ffc173de4..e4599160b 100644 --- a/dom/ts-bindgen/src/typescript/enums.rs +++ b/dom/ts-bindgen/src/typescript/enums.rs @@ -9,18 +9,7 @@ pub struct Enum { impl From> for Enum { fn from(decls: Vec) -> Self { - Enum { - members: decls - .into_iter() - .map(|member| { - let member_name = member_name(&member.id); - if member.init.is_some() { - println!("TODO enum member init {:?}", &member_name); - } - member_name - }) - .collect(), - } + Enum { members: decls.into_iter().map(|member| member_name(&member.id)).collect() } } } From 63abb32cb6f616f56e8cb23f7d1605b9a35c0ba5 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 15:35:37 -0700 Subject: [PATCH 20/41] [ts-bindgen] compact module.rs now that we know what's needed for vscode's index.d.ts --- dom/ts-bindgen/src/typescript/module.rs | 141 ++++++------------------ 1 file changed, 36 insertions(+), 105 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index 8884d1224..b4b43e4bd 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -4,10 +4,8 @@ use std::{ fmt::{Debug, Formatter, Result as FmtResult}, }; use swc_ecma_ast::{ - ClassDecl, Decl, ExportAll, ExportDefaultDecl, ExportDefaultExpr, FnDecl, ImportDecl, Module, - ModuleDecl, ModuleItem, NamedExport, Pat, Stmt, TsEnumDecl, TsExportAssignment, - TsImportEqualsDecl, TsInterfaceDecl, TsModuleDecl, TsModuleName, TsNamespaceBody, - TsNamespaceDecl, TsNamespaceExportDecl, TsTypeAliasDecl, VarDecl, + Decl, Ident, Module, ModuleDecl, ModuleItem, Stmt, TsModuleDecl, TsModuleName, TsNamespaceBody, + TsNamespaceDecl, }; use super::{class::Class, enums::Enum, func::Func, interface::Interface, name::Name, ty::Ty}; @@ -60,120 +58,53 @@ impl TsModule { for item in contents { match item { ModuleItem::ModuleDecl(decl) => match decl { - ModuleDecl::Import(import) => self.add_import(import), + ModuleDecl::Import(_) => todo!("support imports"), + ModuleDecl::ExportNamed(_) => todo!("support re-exports"), + ModuleDecl::ExportDefaultDecl(_) => todo!("export default decl"), + ModuleDecl::ExportDefaultExpr(_) => todo!("export default expr"), + ModuleDecl::ExportAll(_) => todo!("export all"), + ModuleDecl::TsImportEquals(_) => todo!("ts import"), + ModuleDecl::TsExportAssignment(_) => todo!("export assignment"), + ModuleDecl::TsNamespaceExport(_) => todo!("typescript namespace export"), ModuleDecl::ExportDecl(export) => self.add_decl(export.decl), - ModuleDecl::ExportNamed(named) => self.add_named_export(named), - ModuleDecl::ExportDefaultDecl(default_decl) => { - self.add_default_export(default_decl) - } - ModuleDecl::ExportDefaultExpr(expr) => self.add_default_export_expr(expr), - ModuleDecl::ExportAll(export_all) => self.add_export_all(export_all), - - ModuleDecl::TsImportEquals(ts_import) => self.add_import_equals(ts_import), - ModuleDecl::TsExportAssignment(ts_export) => self.add_export_assign(ts_export), - ModuleDecl::TsNamespaceExport(ts_ns_export) => { - self.add_namespace_export(ts_ns_export) - } }, - ModuleItem::Stmt(stmt) => self.add_stmt(stmt), - } - } - } - - fn add_import(&mut self, _import: ImportDecl) { - todo!("support imports"); - } - - pub fn add_named_export(&mut self, _named: NamedExport) { - todo!("support re-exports"); - } - - pub fn add_default_export(&mut self, _default_decl: ExportDefaultDecl) { - todo!("export default decl"); - } - - pub fn add_default_export_expr(&mut self, _default_expr: ExportDefaultExpr) { - todo!("export default expr"); - } - - pub fn add_export_all(&mut self, _export_all: ExportAll) { - todo!("export all"); - } - - pub fn add_import_equals(&mut self, _ts_import: TsImportEqualsDecl) { - todo!("ts import"); - } - - pub fn add_export_assign(&mut self, _ts_export: TsExportAssignment) { - todo!("export assignment"); - } - - pub fn add_namespace_export(&mut self, _ts_ns_export: TsNamespaceExportDecl) { - todo!("typescript namespace export"); - } - - fn add_stmt(&mut self, stmt: Stmt) { - match stmt { - Stmt::Decl(decl) => self.add_decl(decl), - _ => { - todo!("non-decl statements"); + ModuleItem::Stmt(Stmt::Decl(decl)) => self.add_decl(decl), + ModuleItem::Stmt(s) => todo!("support non-decl statements? {:#?}", s), } } } fn add_decl(&mut self, decl: Decl) { match decl { - Decl::Class(class) => self.add_class(class), - Decl::TsInterface(interface) => self.add_interface(interface), - Decl::TsTypeAlias(alias) => self.add_alias(alias), - Decl::TsEnum(ts_enum) => self.add_enum(ts_enum), - Decl::TsModule(TsModuleDecl { id, body, .. }) => self.add_ts_module(id, body), - Decl::Fn(fun) => self.add_function(fun), - Decl::Var(var) => self.add_var(var), - } - } - - fn add_var(&mut self, var: VarDecl) { - for decl in var.decls { - let (name, ty) = match decl.name { - Pat::Ident(n) => ( - Name::from(n.sym.to_string()), - n.type_ann.map(Ty::from).unwrap_or_else(Ty::any), - ), - other => { - todo!("i guess implement support for assignments to {:?}", other); + Decl::Class(class) => { + self.classes.insert(class.ident.sym.to_string().into(), class.class.into()); + } + Decl::TsInterface(interface) => { + self.interfaces.insert(interface.id.sym.to_string().into(), interface.body.into()); + } + Decl::TsTypeAlias(alias) => { + self.aliases.insert(alias.id.sym.to_string().into(), From::from(*alias.type_ann)); + } + Decl::TsEnum(decl) => { + self.enums.insert(decl.id.sym.to_string().into(), decl.members.into()); + } + Decl::Fn(fun) => { + self.functions.insert(fun.ident.sym.to_string().into(), fun.function.into()); + } + Decl::Var(var) => { + for decl in var.decls { + let Ident { sym, type_ann, .. } = decl.name.expect_ident(); + let (name, ty) = ( + Name::from(sym.to_string()), + type_ann.map(Ty::from).unwrap_or_else(Ty::any), + ); + self.variables.insert(name, ty); } - }; - - if let Some(init) = decl.init { - todo!("i guess support initializing {:?} {:?} {:?}", &var.kind, name, init); } - - self.variables.insert(name, ty); + Decl::TsModule(TsModuleDecl { id, body, .. }) => self.add_ts_module(id, body), } } - fn add_function(&mut self, fun: FnDecl) { - let name = Name::from(fun.ident.sym.to_string()); - self.functions.insert(name, fun.function.into()); - } - - fn add_class(&mut self, class: ClassDecl) { - self.classes.insert(class.ident.sym.to_string().into(), class.class.into()); - } - - fn add_interface(&mut self, interface: TsInterfaceDecl) { - self.interfaces.insert(interface.id.sym.to_string().into(), interface.body.into()); - } - - fn add_alias(&mut self, alias: TsTypeAliasDecl) { - self.aliases.insert(alias.id.sym.to_string().into(), From::from(*alias.type_ann)); - } - - fn add_enum(&mut self, decl: TsEnumDecl) { - self.enums.insert(decl.id.sym.to_string().into(), decl.members.into()); - } - fn add_ts_module(&mut self, id: TsModuleName, body: Option) { let new_child = self.children.entry(module_name(&id)).or_insert_with(TsModule::blank); From 451a0efee2c8785932717a54adf2134045b7b140 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 15:50:25 -0700 Subject: [PATCH 21/41] [ts-bindgen] identify which type variants we need to support for vscode --- dom/ts-bindgen/src/typescript/ty.rs | 65 ++++++----------------------- 1 file changed, 13 insertions(+), 52 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 5b1292a7f..2351ddfe0 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -20,10 +20,6 @@ impl From for Ty { println!("TODO keyword types"); Ty::any() } - TsType::TsThisType(_) => { - println!("TODO handle `this` in type annotation??"); - Ty::any() - } TsType::TsFnOrConstructorType(_) => { println!("TODO function or ctor type in annotation"); Ty::any() @@ -32,10 +28,6 @@ impl From for Ty { println!("TODO type reference in annotations"); Ty::any() } - TsType::TsTypeQuery(q) => { - println!("TODO type queries in annotations"); - Ty::any() - } TsType::TsTypeLit(l) => { println!("TODO type literals in annotations"); Ty::any() @@ -48,54 +40,23 @@ impl From for Ty { println!("TODO tuple types in annotations"); Ty::any() } - TsType::TsOptionalType(o) => { - println!("TODO optional types in annotations"); - Ty::any() - } - TsType::TsRestType(r) => { - println!("TODO rest types in annotations"); - Ty::any() - } TsType::TsUnionOrIntersectionType(u) => { println!("TODO union/intersect types in annotations"); Ty::any() } - TsType::TsConditionalType(c) => { - println!("TODO conditional types in annotations"); - Ty::any() - } - TsType::TsInferType(i) => { - println!("TODO inferred types in annotations"); - Ty::any() - } - TsType::TsParenthesizedType(p) => { - println!("TODO paren'sized types in annotations"); - Ty::any() - } - TsType::TsTypeOperator(o) => { - println!("TODO type operators in annotations"); - Ty::any() - } - TsType::TsIndexedAccessType(i) => { - println!("TODO indexed access types in annotations"); - Ty::any() - } - TsType::TsMappedType(m) => { - println!("TODO mapped types in annotations"); - Ty::any() - } - TsType::TsLitType(l) => { - println!("TODO literal types in annotations"); - Ty::any() - } - TsType::TsTypePredicate(p) => { - println!("TODO predicates in annotations"); - Ty::any() - } - TsType::TsImportType(i) => { - println!("TODO import types in annotations"); - Ty::any() - } + TsType::TsOptionalType(o) => todo!("optional types"), + TsType::TsRestType(r) => todo!("rest types"), + TsType::TsTypeQuery(q) => todo!("type queries"), + TsType::TsThisType(_) => todo!("`this`"), + TsType::TsConditionalType(c) => todo!("conditional types"), + TsType::TsInferType(i) => todo!("inferred types"), + TsType::TsParenthesizedType(p) => todo!("paren'sized types"), + TsType::TsTypeOperator(o) => todo!("type operators"), + TsType::TsIndexedAccessType(i) => todo!("indexed access types"), + TsType::TsMappedType(m) => todo!("mapped types"), + TsType::TsLitType(l) => todo!("literal types"), + TsType::TsTypePredicate(p) => todo!("predicates"), + TsType::TsImportType(i) => todo!("import types"), } } } From 897868c6b1757afade787784fdf152d94db0513a Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 16:21:43 -0700 Subject: [PATCH 22/41] [ts-bindgen] start implementing basic Ty's also make constructors return the class they're defined w/ instead of Any --- dom/ts-bindgen/src/typescript/class.rs | 24 +++--- dom/ts-bindgen/src/typescript/func.rs | 6 +- dom/ts-bindgen/src/typescript/module.rs | 8 +- dom/ts-bindgen/src/typescript/param.rs | 4 +- dom/ts-bindgen/src/typescript/ty.rs | 102 +++++++++++++++++------- 5 files changed, 93 insertions(+), 51 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index 9386e048f..4127dba69 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -2,33 +2,33 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::{Class as AstClass, ClassMember, ClassMethod, Constructor, PropName}; +use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, Constructor, PropName}; -use super::{Func, Name, Ty}; +use super::{Func, Name}; pub struct Class { - ty: Ty, constructors: Vec, statics: BTreeMap, methods: BTreeMap, } -impl From for Class { - fn from(class: AstClass) -> Self { +impl From for Class { + fn from(class: ClassDecl) -> Self { let mut new = Class { - ty: Ty::any(), // TODO a real type? constructors: Default::default(), statics: Default::default(), methods: Default::default(), }; + let name = Name::from(class.ident.sym.to_string()); + // TODO type params // TODO super class & type params // TODO implemented interfaces - for member in class.body { + for member in class.class.body { match member { - ClassMember::Constructor(ctor) => new.add_constructor(ctor), + ClassMember::Constructor(ctor) => new.add_constructor(&name, ctor), ClassMember::Method(method) => new.add_method(method), ClassMember::ClassProp(_) => println!("TODO class properties?"), ClassMember::PrivateMethod(_) => todo!("private methods"), @@ -43,12 +43,8 @@ impl From for Class { } impl Class { - pub fn ty(&self) -> &Ty { - &self.ty - } - - fn add_constructor(&mut self, ctor: Constructor) { - self.constructors.push(Func::ctor(&self, ctor.params)); + fn add_constructor(&mut self, name: &Name, ctor: Constructor) { + self.constructors.push(Func::ctor(name, ctor.params)); } fn add_method(&mut self, method: ClassMethod) { diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index e524b7661..83a701bcc 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; use swc_ecma_ast::{Function, ParamOrTsParamProp}; -use super::{Class, TsParam, Ty}; +use super::{Name, TsParam, Ty}; pub struct Func { is_generator: bool, @@ -11,7 +11,7 @@ pub struct Func { } impl Func { - pub fn ctor(class: &Class, params: Vec) -> Self { + pub fn ctor(name: &Name, params: Vec) -> Self { Self { is_async: false, is_generator: false, @@ -24,7 +24,7 @@ impl Func { } }) .collect(), - returns: Some(class.ty().clone()), + returns: Some(Ty::Named(name.clone())), } } } diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index b4b43e4bd..f230be8a6 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -77,7 +77,7 @@ impl TsModule { fn add_decl(&mut self, decl: Decl) { match decl { Decl::Class(class) => { - self.classes.insert(class.ident.sym.to_string().into(), class.class.into()); + self.classes.insert(class.ident.sym.to_string().into(), class.into()); } Decl::TsInterface(interface) => { self.interfaces.insert(interface.id.sym.to_string().into(), interface.body.into()); @@ -94,10 +94,8 @@ impl TsModule { Decl::Var(var) => { for decl in var.decls { let Ident { sym, type_ann, .. } = decl.name.expect_ident(); - let (name, ty) = ( - Name::from(sym.to_string()), - type_ann.map(Ty::from).unwrap_or_else(Ty::any), - ); + let (name, ty) = + (Name::from(sym.to_string()), type_ann.map(Ty::from).unwrap_or(Ty::Any)); self.variables.insert(name, ty); } } diff --git a/dom/ts-bindgen/src/typescript/param.rs b/dom/ts-bindgen/src/typescript/param.rs index bd79a2a83..9910ff28c 100644 --- a/dom/ts-bindgen/src/typescript/param.rs +++ b/dom/ts-bindgen/src/typescript/param.rs @@ -15,12 +15,12 @@ impl From for TsParam { match param.pat { Pat::Ident(i) => { let name = i.sym.to_string().into(); - let ty = i.type_ann.map(Ty::from).unwrap_or_else(Ty::any); + let ty = i.type_ann.map(Ty::from).unwrap_or(Ty::Any); Self { name, ty, rest: false, optional: i.optional } } Pat::Rest(r) => { let name = r.arg.expect_ident().sym.to_string().into(); - let ty = r.type_ann.map(Ty::from).unwrap_or_else(Ty::any); + let ty = r.type_ann.map(Ty::from).unwrap_or(Ty::Any); Self { name, ty, rest: true, optional: false } } other => todo!("other parameter types like {:#?}", other), diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 2351ddfe0..e3ea7915f 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,48 +1,69 @@ #![allow(unused)] -use swc_ecma_ast::{TsType, TsTypeAnn}; +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use swc_ecma_ast::{TsEntityName, TsKeywordTypeKind, TsType, TsTypeAnn}; -#[derive(Clone, Debug)] -pub struct Ty { - // TODO figure out a better repr for not-yet-resolved types -} +use super::Name; -impl Ty { - pub fn any() -> Self { - Ty {} - } +#[derive(Clone)] +pub enum Ty { + Any, + Unknown, + Number, + Object, + Boolean, + BigInt, + String, + Symbol, + Void, + Undefined, + Null, + Never, + Array(Box), + Tuple(Vec), + Named(Name), } impl From for Ty { fn from(ty: TsType) -> Ty { match ty { - TsType::TsKeywordType(kw) => { - println!("TODO keyword types"); - Ty::any() - } + TsType::TsKeywordType(kw) => match kw.kind { + TsKeywordTypeKind::TsAnyKeyword => Ty::Any, + TsKeywordTypeKind::TsUnknownKeyword => Ty::Unknown, + TsKeywordTypeKind::TsNumberKeyword => Ty::Number, + TsKeywordTypeKind::TsObjectKeyword => Ty::Object, + TsKeywordTypeKind::TsBooleanKeyword => Ty::Boolean, + TsKeywordTypeKind::TsBigIntKeyword => Ty::BigInt, + TsKeywordTypeKind::TsStringKeyword => Ty::String, + TsKeywordTypeKind::TsSymbolKeyword => Ty::Symbol, + TsKeywordTypeKind::TsVoidKeyword => Ty::Void, + TsKeywordTypeKind::TsUndefinedKeyword => Ty::Undefined, + TsKeywordTypeKind::TsNullKeyword => Ty::Null, + TsKeywordTypeKind::TsNeverKeyword => Ty::Never, + }, TsType::TsFnOrConstructorType(_) => { println!("TODO function or ctor type in annotation"); - Ty::any() - } - TsType::TsTypeRef(r) => { - println!("TODO type reference in annotations"); - Ty::any() + Ty::Any } + TsType::TsTypeRef(r) => Ty::Named(match r.type_name { + TsEntityName::Ident(i) => i.sym.to_string().into(), + TsEntityName::TsQualifiedName(n) => todo!("qualified type references"), + }), TsType::TsTypeLit(l) => { println!("TODO type literals in annotations"); - Ty::any() - } - TsType::TsArrayType(a) => { - println!("TODO array types in annotations"); - Ty::any() + Ty::Any } + TsType::TsArrayType(a) => Ty::Array(Box::new((*a.elem_type).into())), TsType::TsTupleType(t) => { - println!("TODO tuple types in annotations"); - Ty::any() + Ty::Tuple(t.elem_types.into_iter().map(|t| t.ty.into()).collect()) } TsType::TsUnionOrIntersectionType(u) => { println!("TODO union/intersect types in annotations"); - Ty::any() + Ty::Any + } + TsType::TsParenthesizedType(p) => { + println!("TODO paren'sized types"); + Ty::Any } TsType::TsOptionalType(o) => todo!("optional types"), TsType::TsRestType(r) => todo!("rest types"), @@ -50,7 +71,6 @@ impl From for Ty { TsType::TsThisType(_) => todo!("`this`"), TsType::TsConditionalType(c) => todo!("conditional types"), TsType::TsInferType(i) => todo!("inferred types"), - TsType::TsParenthesizedType(p) => todo!("paren'sized types"), TsType::TsTypeOperator(o) => todo!("type operators"), TsType::TsIndexedAccessType(i) => todo!("indexed access types"), TsType::TsMappedType(m) => todo!("mapped types"), @@ -66,3 +86,31 @@ impl From for Ty { (*ann.type_ann).into() } } + +impl Debug for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + Ty::Any => write!(f, "Any"), + Ty::Unknown => write!(f, "Unknown"), + Ty::Number => write!(f, "Number"), + Ty::Object => write!(f, "Object"), + Ty::Boolean => write!(f, "Boolean"), + Ty::BigInt => write!(f, "BigInt"), + Ty::String => write!(f, "String"), + Ty::Symbol => write!(f, "Symbol"), + Ty::Void => write!(f, "Void"), + Ty::Undefined => write!(f, "undefined"), + Ty::Null => write!(f, "null"), + Ty::Never => write!(f, "!"), + Ty::Array(elem) => write!(f, "Array<{:?}>", elem), + Ty::Tuple(tup) => { + let mut f = f.debug_tuple(""); + for ty in tup { + f.field(ty); + } + f.finish() + } + Ty::Named(name) => write!(f, "{}", name), + } + } +} From 6fb2de3bdf19ce535478d0f2ade6f5342016e7c0 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 4 Sep 2020 17:59:04 -0700 Subject: [PATCH 23/41] [ts-bindgen] fn and ctor types --- dom/ts-bindgen/src/typescript/func.rs | 25 ++++++++++++++++++++++++- dom/ts-bindgen/src/typescript/param.rs | 24 ++++++++++++++++++++++-- dom/ts-bindgen/src/typescript/ty.rs | 24 ++++++++++++++---------- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index 83a701bcc..632c468b1 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -1,8 +1,9 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::{Function, ParamOrTsParamProp}; +use swc_ecma_ast::{Function, ParamOrTsParamProp, TsConstructorType, TsFnType}; use super::{Name, TsParam, Ty}; +#[derive(Clone)] pub struct Func { is_generator: bool, is_async: bool, @@ -40,6 +41,28 @@ impl From for Func { } } +impl From for Func { + fn from(function: TsFnType) -> Self { + Self { + is_generator: false, + is_async: false, + returns: Some(function.type_ann.into()), + params: function.params.into_iter().map(From::from).collect(), + } + } +} + +impl From for Func { + fn from(function: TsConstructorType) -> Self { + Self { + is_generator: false, + is_async: false, + returns: Some(function.type_ann.into()), + params: function.params.into_iter().map(From::from).collect(), + } + } +} + impl Debug for Func { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let asyncness = if self.is_async { "async " } else { "" }; diff --git a/dom/ts-bindgen/src/typescript/param.rs b/dom/ts-bindgen/src/typescript/param.rs index 9910ff28c..42ab4523e 100644 --- a/dom/ts-bindgen/src/typescript/param.rs +++ b/dom/ts-bindgen/src/typescript/param.rs @@ -1,8 +1,9 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::{Param, Pat}; +use swc_ecma_ast::{Param, Pat, TsFnParam}; use super::{name::Name, ty::Ty}; +#[derive(Clone)] pub struct TsParam { name: Name, optional: bool, @@ -11,7 +12,7 @@ pub struct TsParam { } impl From for TsParam { - fn from(param: Param) -> TsParam { + fn from(param: Param) -> Self { match param.pat { Pat::Ident(i) => { let name = i.sym.to_string().into(); @@ -28,6 +29,25 @@ impl From for TsParam { } } +impl From for TsParam { + fn from(param: TsFnParam) -> Self { + match param { + TsFnParam::Ident(i) => { + let name = i.sym.to_string().into(); + let ty = i.type_ann.map(Ty::from).unwrap_or(Ty::Any); + TsParam { name, ty, rest: false, optional: i.optional } + } + TsFnParam::Rest(r) => { + let name = r.arg.expect_ident().sym.to_string().into(); + let ty = r.type_ann.map(Ty::from).unwrap_or(Ty::Any); + TsParam { name, ty, rest: true, optional: false } + } + TsFnParam::Array(_) => todo!("typescript array function parameters"), + TsFnParam::Object(_) => todo!("typescript object function parameters"), + } + } +} + impl Debug for TsParam { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let rest = if self.rest { "..." } else { "" }; diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index e3ea7915f..00e2a3be6 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,9 +1,9 @@ #![allow(unused)] use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::{TsEntityName, TsKeywordTypeKind, TsType, TsTypeAnn}; +use swc_ecma_ast::{TsEntityName, TsFnOrConstructorType, TsKeywordTypeKind, TsType, TsTypeAnn}; -use super::Name; +use super::{Func, Name}; #[derive(Clone)] pub enum Ty { @@ -22,6 +22,8 @@ pub enum Ty { Array(Box), Tuple(Vec), Named(Name), + Fn(Box), + Ctor(Box), } impl From for Ty { @@ -41,22 +43,22 @@ impl From for Ty { TsKeywordTypeKind::TsNullKeyword => Ty::Null, TsKeywordTypeKind::TsNeverKeyword => Ty::Never, }, - TsType::TsFnOrConstructorType(_) => { - println!("TODO function or ctor type in annotation"); - Ty::Any - } TsType::TsTypeRef(r) => Ty::Named(match r.type_name { TsEntityName::Ident(i) => i.sym.to_string().into(), TsEntityName::TsQualifiedName(n) => todo!("qualified type references"), }), - TsType::TsTypeLit(l) => { - println!("TODO type literals in annotations"); - Ty::Any - } TsType::TsArrayType(a) => Ty::Array(Box::new((*a.elem_type).into())), TsType::TsTupleType(t) => { Ty::Tuple(t.elem_types.into_iter().map(|t| t.ty.into()).collect()) } + TsType::TsFnOrConstructorType(fn_or_ctor) => match fn_or_ctor { + TsFnOrConstructorType::TsFnType(func) => Ty::Fn(Box::new(func.into())), + TsFnOrConstructorType::TsConstructorType(ctor) => Ty::Ctor(Box::new(ctor.into())), + }, + TsType::TsTypeLit(l) => { + println!("TODO type literals in annotations"); + Ty::Any + } TsType::TsUnionOrIntersectionType(u) => { println!("TODO union/intersect types in annotations"); Ty::Any @@ -111,6 +113,8 @@ impl Debug for Ty { f.finish() } Ty::Named(name) => write!(f, "{}", name), + Ty::Fn(fun) => write!(f, "{:?}", fun), + Ty::Ctor(ctor) => write!(f, "new {:?}", ctor), } } } From 51c4abf3ca7f51b168bb2b1f9fe44f81ffdfd4ef Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 10:23:08 -0700 Subject: [PATCH 24/41] [ts-bindgen] almost the rest of the parsing owl qualified names type literals unions intersections parenthesized types --- dom/ts-bindgen/src/typescript/name.rs | 43 +++++++++++++++++--- dom/ts-bindgen/src/typescript/ty.rs | 57 ++++++++++++++++++++------- 2 files changed, 79 insertions(+), 21 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/name.rs b/dom/ts-bindgen/src/typescript/name.rs index cac378182..23bbccb4e 100644 --- a/dom/ts-bindgen/src/typescript/name.rs +++ b/dom/ts-bindgen/src/typescript/name.rs @@ -1,28 +1,59 @@ use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; +use swc_ecma_ast::TsEntityName; #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] -pub struct Name(String); +pub struct Name { + segments: Vec, + dotted: String, +} impl From for Name { - fn from(s: String) -> Self { - Name(s.to_string()) + fn from(dotted: String) -> Self { + let segments = dotted.split(".").map(ToString::to_string).collect(); + Self { segments, dotted } + } +} + +impl From> for Name { + fn from(segments: Vec) -> Self { + let dotted = segments.join("."); + Self { segments, dotted } + } +} + +impl From for Name { + fn from(entity: TsEntityName) -> Self { + let mut segments = Vec::new(); + push_name_segments(entity, &mut segments); + let dotted = segments.join("."); + Self { segments, dotted } + } +} + +fn push_name_segments(name: TsEntityName, segments: &mut Vec) { + match name { + TsEntityName::Ident(i) => segments.push(i.sym.to_string()), + TsEntityName::TsQualifiedName(qualified) => { + push_name_segments(qualified.left, segments); + segments.push(qualified.right.sym.to_string()); + } } } impl AsRef for Name { fn as_ref(&self) -> &str { - &self.0 + &self.dotted } } impl Debug for Name { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(&self.0) + f.write_str(&self.dotted) } } impl Display for Name { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(&self.0) + f.write_str(&self.dotted) } } diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 00e2a3be6..572927952 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,7 +1,10 @@ #![allow(unused)] use std::fmt::{Debug, Formatter, Result as FmtResult}; -use swc_ecma_ast::{TsEntityName, TsFnOrConstructorType, TsKeywordTypeKind, TsType, TsTypeAnn}; +use swc_ecma_ast::{ + TsEntityName, TsFnOrConstructorType, TsKeywordTypeKind, TsType, TsTypeAnn, TsTypeElement, + TsUnionOrIntersectionType, +}; use super::{Func, Name}; @@ -24,6 +27,9 @@ pub enum Ty { Named(Name), Fn(Box), Ctor(Box), + Lit(Vec), + Union(Vec), + Intersection(Vec), } impl From for Ty { @@ -43,10 +49,7 @@ impl From for Ty { TsKeywordTypeKind::TsNullKeyword => Ty::Null, TsKeywordTypeKind::TsNeverKeyword => Ty::Never, }, - TsType::TsTypeRef(r) => Ty::Named(match r.type_name { - TsEntityName::Ident(i) => i.sym.to_string().into(), - TsEntityName::TsQualifiedName(n) => todo!("qualified type references"), - }), + TsType::TsTypeRef(r) => Ty::Named(r.type_name.into()), TsType::TsArrayType(a) => Ty::Array(Box::new((*a.elem_type).into())), TsType::TsTupleType(t) => { Ty::Tuple(t.elem_types.into_iter().map(|t| t.ty.into()).collect()) @@ -55,18 +58,14 @@ impl From for Ty { TsFnOrConstructorType::TsFnType(func) => Ty::Fn(Box::new(func.into())), TsFnOrConstructorType::TsConstructorType(ctor) => Ty::Ctor(Box::new(ctor.into())), }, - TsType::TsTypeLit(l) => { - println!("TODO type literals in annotations"); - Ty::Any + TsType::TsTypeLit(l) => Ty::Lit(l.members.into_iter().map(Ty::from).collect()), + TsType::TsUnionOrIntersectionType(TsUnionOrIntersectionType::TsUnionType(u)) => { + Ty::Union(u.types.into_iter().map(|t| Ty::from(*t)).collect()) } - TsType::TsUnionOrIntersectionType(u) => { - println!("TODO union/intersect types in annotations"); - Ty::Any - } - TsType::TsParenthesizedType(p) => { - println!("TODO paren'sized types"); - Ty::Any + TsType::TsUnionOrIntersectionType(TsUnionOrIntersectionType::TsIntersectionType(i)) => { + Ty::Intersection(i.types.into_iter().map(|t| Ty::from(*t)).collect()) } + TsType::TsParenthesizedType(p) => Ty::from(*p.type_ann), TsType::TsOptionalType(o) => todo!("optional types"), TsType::TsRestType(r) => todo!("rest types"), TsType::TsTypeQuery(q) => todo!("type queries"), @@ -83,6 +82,19 @@ impl From for Ty { } } +impl From for Ty { + fn from(elem: TsTypeElement) -> Self { + println!("TODO type element"); + match elem { + TsTypeElement::TsPropertySignature(p) => Ty::Any, + TsTypeElement::TsCallSignatureDecl(c) => Ty::Any, + TsTypeElement::TsConstructSignatureDecl(c) => Ty::Any, + TsTypeElement::TsMethodSignature(m) => Ty::Any, + TsTypeElement::TsIndexSignature(i) => Ty::Any, + } + } +} + impl From for Ty { fn from(ann: TsTypeAnn) -> Ty { (*ann.type_ann).into() @@ -115,6 +127,21 @@ impl Debug for Ty { Ty::Named(name) => write!(f, "{}", name), Ty::Fn(fun) => write!(f, "{:?}", fun), Ty::Ctor(ctor) => write!(f, "new {:?}", ctor), + Ty::Lit(members) => f.debug_set().entries(members).finish(), + Ty::Union(members) => { + let mut tup = f.debug_tuple("∪"); + for m in members { + tup.field(m); + } + tup.finish() + } + Ty::Intersection(members) => { + let mut tup = f.debug_tuple("∩"); + for m in members { + tup.field(m); + } + tup.finish() + } } } } From 554c58c7a9f138a1a5df64eb09e1fc82fd604c26 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 10:38:10 -0700 Subject: [PATCH 25/41] [ts-bindgen] class properties --- dom/ts-bindgen/src/typescript/class.rs | 23 ++++++++++++++++------- dom/ts-bindgen/src/typescript/ty.rs | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index 4127dba69..bb2d9a3d6 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -2,12 +2,13 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, Constructor, PropName}; +use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, ClassProp, Constructor, Expr, PropName}; -use super::{Func, Name}; +use super::{Func, Name, Ty}; pub struct Class { constructors: Vec, + properties: BTreeMap, statics: BTreeMap, methods: BTreeMap, } @@ -16,6 +17,7 @@ impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { constructors: Default::default(), + properties: Default::default(), statics: Default::default(), methods: Default::default(), }; @@ -30,7 +32,7 @@ impl From for Class { match member { ClassMember::Constructor(ctor) => new.add_constructor(&name, ctor), ClassMember::Method(method) => new.add_method(method), - ClassMember::ClassProp(_) => println!("TODO class properties?"), + ClassMember::ClassProp(prop) => new.add_property(prop), ClassMember::PrivateMethod(_) => todo!("private methods"), ClassMember::PrivateProp(_) => todo!("private properties"), ClassMember::TsIndexSignature(_) => todo!("ts index signatures"), @@ -57,20 +59,27 @@ impl Class { self.methods.insert(name, func); } } + + fn add_property(&mut self, prop: ClassProp) { + let name = match *prop.key { + Expr::Ident(i) => i.sym.to_string().into(), + other => panic!("only ident exprs supported for property keys, found: {:?}", other), + }; + self.properties.insert(name, prop.type_ann.map(Ty::from).unwrap_or(Ty::Any)); + } } impl Debug for Class { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let mut f = f.debug_map(); + f.entries(&self.properties); let ctor_name = Name::from("contructor".to_string()); for ctor in &self.constructors { f.entry(&ctor_name, &ctor); } - f.entries(&self.statics); - f.entries(&self.methods); - f.finish() + f.entries(&self.statics).entries(&self.methods).finish() } } @@ -79,6 +88,6 @@ fn prop_name(key: PropName) -> Name { PropName::Ident(i) => i.sym.to_string().into(), PropName::Str(s) => s.value.to_string().into(), PropName::Num(n) => n.value.to_string().into(), - PropName::Computed(c) => todo!("support computed property names: {:#?}", c), + PropName::Computed(c) => todo!("computed property names: {:#?}", c), } } diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 572927952..5292a5dc5 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -82,9 +82,9 @@ impl From for Ty { } } +// TODO make traits from interfaces impl From for Ty { fn from(elem: TsTypeElement) -> Self { - println!("TODO type element"); match elem { TsTypeElement::TsPropertySignature(p) => Ty::Any, TsTypeElement::TsCallSignatureDecl(c) => Ty::Any, From c2cd2cc169208c8c9101eaf99fcaee113658e25a Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 10:40:15 -0700 Subject: [PATCH 26/41] inline unnecessarily outlined function --- dom/ts-bindgen/src/typescript/class.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index bb2d9a3d6..dee120c4c 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -50,7 +50,12 @@ impl Class { } fn add_method(&mut self, method: ClassMethod) { - let name = prop_name(method.key); + let name = match method.key { + PropName::Ident(i) => i.sym.to_string().into(), + PropName::Str(s) => s.value.to_string().into(), + PropName::Num(n) => n.value.to_string().into(), + PropName::Computed(c) => todo!("computed property names: {:#?}", c), + }; let func = Func::from(method.function); if method.is_static { @@ -82,12 +87,3 @@ impl Debug for Class { f.entries(&self.statics).entries(&self.methods).finish() } } - -fn prop_name(key: PropName) -> Name { - match key { - PropName::Ident(i) => i.sym.to_string().into(), - PropName::Str(s) => s.value.to_string().into(), - PropName::Num(n) => n.value.to_string().into(), - PropName::Computed(c) => todo!("computed property names: {:#?}", c), - } -} From 95edf7c08bea5bbf9ed5d85b8e62ca2631fcaee8 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 11:55:02 -0700 Subject: [PATCH 27/41] [ts-bindgen] classes have type parameters --- dom/ts-bindgen/src/typescript.rs | 2 +- dom/ts-bindgen/src/typescript/class.rs | 23 ++++++++++++++++--- dom/ts-bindgen/src/typescript/ty.rs | 31 +++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/dom/ts-bindgen/src/typescript.rs b/dom/ts-bindgen/src/typescript.rs index 0d90b2d29..92cfbcd23 100644 --- a/dom/ts-bindgen/src/typescript.rs +++ b/dom/ts-bindgen/src/typescript.rs @@ -19,7 +19,7 @@ pub use interface::Interface; pub use module::TsModule; pub use name::Name; pub use param::TsParam; -pub use ty::Ty; +pub use ty::{Ty, TyParam}; pub fn parse_d_ts(contents: &str) -> Result { let input = StringInput::new(contents, BytePos(0), BytePos(0)); diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index dee120c4c..902e2d90b 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -2,11 +2,14 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, ClassProp, Constructor, Expr, PropName}; +use swc_ecma_ast::{ + ClassDecl, ClassMember, ClassMethod, ClassProp, Constructor, Expr, PropName, TsTypeParam, +}; -use super::{Func, Name, Ty}; +use super::{Func, Name, Ty, TyParam}; pub struct Class { + ty_params: BTreeMap, constructors: Vec, properties: BTreeMap, statics: BTreeMap, @@ -16,6 +19,7 @@ pub struct Class { impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { + ty_params: Default::default(), constructors: Default::default(), properties: Default::default(), statics: Default::default(), @@ -24,7 +28,12 @@ impl From for Class { let name = Name::from(class.ident.sym.to_string()); - // TODO type params + if let Some(types) = class.class.type_params { + for p in types.params { + new.add_ty_param(p); + } + } + // TODO super class & type params // TODO implemented interfaces @@ -45,6 +54,10 @@ impl From for Class { } impl Class { + fn add_ty_param(&mut self, param: TsTypeParam) { + self.ty_params.insert(param.name.sym.to_string().into(), TyParam::from(param)); + } + fn add_constructor(&mut self, name: &Name, ctor: Constructor) { self.constructors.push(Func::ctor(name, ctor.params)); } @@ -76,6 +89,10 @@ impl Class { impl Debug for Class { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + if !self.ty_params.is_empty() { + f.debug_map().entries(&self.ty_params).finish()?; + } + let mut f = f.debug_map(); f.entries(&self.properties); diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 5292a5dc5..f67ef691d 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; use swc_ecma_ast::{ TsEntityName, TsFnOrConstructorType, TsKeywordTypeKind, TsType, TsTypeAnn, TsTypeElement, - TsUnionOrIntersectionType, + TsTypeParam, TsUnionOrIntersectionType, }; use super::{Func, Name}; @@ -145,3 +145,32 @@ impl Debug for Ty { } } } + +#[derive(Clone)] +pub struct TyParam { + constraint: Option, + default: Option, +} + +impl From for TyParam { + fn from(param: TsTypeParam) -> Self { + Self { + constraint: param.constraint.map(|c| Ty::from(*c)), + default: param.default.map(|d| Ty::from(*d)), + } + } +} + +impl Debug for TyParam { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + if let Some(constraint) = &self.constraint { + write!(f, ": {:?}", constraint)?; + } + + if let Some(default) = &self.default { + write!(f, " = {:?}", default)?; + } + + Ok(()) + } +} From 313cb6f4ae5e25e63a2df08d334970c2293ae64c Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 11:55:47 -0700 Subject: [PATCH 28/41] [ts-bindgen] functions know if they're constructors --- dom/ts-bindgen/src/typescript/func.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index 632c468b1..4da2198b6 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -5,6 +5,7 @@ use super::{Name, TsParam, Ty}; #[derive(Clone)] pub struct Func { + is_ctor: bool, is_generator: bool, is_async: bool, params: Vec, @@ -14,6 +15,7 @@ pub struct Func { impl Func { pub fn ctor(name: &Name, params: Vec) -> Self { Self { + is_ctor: true, is_async: false, is_generator: false, params: params @@ -33,6 +35,7 @@ impl Func { impl From for Func { fn from(function: Function) -> Self { Self { + is_ctor: false, is_async: function.is_async, is_generator: function.is_generator, params: function.params.into_iter().map(From::from).collect(), @@ -44,6 +47,7 @@ impl From for Func { impl From for Func { fn from(function: TsFnType) -> Self { Self { + is_ctor: false, is_generator: false, is_async: false, returns: Some(function.type_ann.into()), @@ -55,6 +59,7 @@ impl From for Func { impl From for Func { fn from(function: TsConstructorType) -> Self { Self { + is_ctor: true, is_generator: false, is_async: false, returns: Some(function.type_ann.into()), @@ -65,9 +70,10 @@ impl From for Func { impl Debug for Func { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let fun = if self.is_ctor { "new" } else { "function" }; let asyncness = if self.is_async { "async " } else { "" }; let genny = if self.is_generator { "*" } else { "" }; - let prelude = format!("{}function{} ", asyncness, genny); + let prelude = format!("{}{}{} ", asyncness, fun, genny); if self.params.is_empty() { write!(f, "{}()", prelude)?; @@ -79,6 +85,6 @@ impl Debug for Func { tup.finish()?; } - if let Some(ret) = &self.returns { write!(f, " -> {:?}", ret) } else { Ok(()) } + if let Some(ret) = &self.returns { write!(f, ": {:?}", ret) } else { Ok(()) } } } From f0a31f3260d789362f8c462d64a1550e85fe61cc Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 13:30:25 -0700 Subject: [PATCH 29/41] [ts-bindgen] functions have type params --- dom/ts-bindgen/src/typescript/class.rs | 16 ++-------------- dom/ts-bindgen/src/typescript/func.rs | 12 ++++++++++-- dom/ts-bindgen/src/typescript/ty.rs | 21 +++++++++++++++++++-- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index 902e2d90b..6ce22369a 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -2,9 +2,7 @@ use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, }; -use swc_ecma_ast::{ - ClassDecl, ClassMember, ClassMethod, ClassProp, Constructor, Expr, PropName, TsTypeParam, -}; +use swc_ecma_ast::{ClassDecl, ClassMember, ClassMethod, ClassProp, Constructor, Expr, PropName}; use super::{Func, Name, Ty, TyParam}; @@ -19,7 +17,7 @@ pub struct Class { impl From for Class { fn from(class: ClassDecl) -> Self { let mut new = Class { - ty_params: Default::default(), + ty_params: TyParam::make_map(class.class.type_params), constructors: Default::default(), properties: Default::default(), statics: Default::default(), @@ -28,12 +26,6 @@ impl From for Class { let name = Name::from(class.ident.sym.to_string()); - if let Some(types) = class.class.type_params { - for p in types.params { - new.add_ty_param(p); - } - } - // TODO super class & type params // TODO implemented interfaces @@ -54,10 +46,6 @@ impl From for Class { } impl Class { - fn add_ty_param(&mut self, param: TsTypeParam) { - self.ty_params.insert(param.name.sym.to_string().into(), TyParam::from(param)); - } - fn add_constructor(&mut self, name: &Name, ctor: Constructor) { self.constructors.push(Func::ctor(name, ctor.params)); } diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index 4da2198b6..b1dc8ac8d 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -1,13 +1,17 @@ -use std::fmt::{Debug, Formatter, Result as FmtResult}; +use std::{ + collections::BTreeMap, + fmt::{Debug, Formatter, Result as FmtResult}, +}; use swc_ecma_ast::{Function, ParamOrTsParamProp, TsConstructorType, TsFnType}; -use super::{Name, TsParam, Ty}; +use super::{Name, TsParam, Ty, TyParam}; #[derive(Clone)] pub struct Func { is_ctor: bool, is_generator: bool, is_async: bool, + ty_params: BTreeMap, params: Vec, returns: Option, } @@ -18,6 +22,7 @@ impl Func { is_ctor: true, is_async: false, is_generator: false, + ty_params: Default::default(), // constructors only have the class' ty params params: params .into_iter() .map(|param| match param { @@ -38,6 +43,7 @@ impl From for Func { is_ctor: false, is_async: function.is_async, is_generator: function.is_generator, + ty_params: TyParam::make_map(function.type_params), params: function.params.into_iter().map(From::from).collect(), returns: function.return_type.map(From::from), } @@ -50,6 +56,7 @@ impl From for Func { is_ctor: false, is_generator: false, is_async: false, + ty_params: TyParam::make_map(function.type_params), returns: Some(function.type_ann.into()), params: function.params.into_iter().map(From::from).collect(), } @@ -62,6 +69,7 @@ impl From for Func { is_ctor: true, is_generator: false, is_async: false, + ty_params: TyParam::make_map(function.type_params), returns: Some(function.type_ann.into()), params: function.params.into_iter().map(From::from).collect(), } diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index f67ef691d..86e227c8f 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,9 +1,12 @@ #![allow(unused)] -use std::fmt::{Debug, Formatter, Result as FmtResult}; +use std::{ + collections::BTreeMap, + fmt::{Debug, Formatter, Result as FmtResult}, +}; use swc_ecma_ast::{ TsEntityName, TsFnOrConstructorType, TsKeywordTypeKind, TsType, TsTypeAnn, TsTypeElement, - TsTypeParam, TsUnionOrIntersectionType, + TsTypeParam, TsTypeParamDecl, TsUnionOrIntersectionType, }; use super::{Func, Name}; @@ -152,6 +155,20 @@ pub struct TyParam { default: Option, } +impl TyParam { + pub fn make_map(opt: Option) -> BTreeMap { + let mut map = BTreeMap::new(); + + if let Some(decl) = opt { + for p in decl.params { + map.insert(p.name.sym.to_string().into(), p.into()); + } + } + + map + } +} + impl From for TyParam { fn from(param: TsTypeParam) -> Self { Self { From c9fb1ce98fd730c7d17aab69051a4f52340556b5 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 16:20:36 -0700 Subject: [PATCH 30/41] [ts-bindge] type params for names --- dom/ts-bindgen/src/typescript/func.rs | 2 +- dom/ts-bindgen/src/typescript/ty.rs | 39 ++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index b1dc8ac8d..e5aee3d0e 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -32,7 +32,7 @@ impl Func { } }) .collect(), - returns: Some(Ty::Named(name.clone())), + returns: Some(Ty::named(name)), } } } diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 86e227c8f..4522e88b9 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -6,7 +6,7 @@ use std::{ }; use swc_ecma_ast::{ TsEntityName, TsFnOrConstructorType, TsKeywordTypeKind, TsType, TsTypeAnn, TsTypeElement, - TsTypeParam, TsTypeParamDecl, TsUnionOrIntersectionType, + TsTypeParam, TsTypeParamDecl, TsTypeParamInstantiation, TsUnionOrIntersectionType, }; use super::{Func, Name}; @@ -27,12 +27,27 @@ pub enum Ty { Never, Array(Box), Tuple(Vec), - Named(Name), Fn(Box), Ctor(Box), Lit(Vec), Union(Vec), Intersection(Vec), + + /// A Named type is basically any reference to another type. + Named { + name: Name, + params: Vec, + }, +} + +impl Ty { + pub fn named(name: &Name) -> Self { + Ty::Named { name: name.clone(), params: Default::default() } + } + + pub fn param_instances(opt: Option) -> Vec { + opt.map(|p| p.params.into_iter().map(|p| Ty::from(*p)).collect()).unwrap_or_default() + } } impl From for Ty { @@ -52,7 +67,9 @@ impl From for Ty { TsKeywordTypeKind::TsNullKeyword => Ty::Null, TsKeywordTypeKind::TsNeverKeyword => Ty::Never, }, - TsType::TsTypeRef(r) => Ty::Named(r.type_name.into()), + TsType::TsTypeRef(r) => { + Ty::Named { name: r.type_name.into(), params: Ty::param_instances(r.type_params) } + } TsType::TsArrayType(a) => Ty::Array(Box::new((*a.elem_type).into())), TsType::TsTupleType(t) => { Ty::Tuple(t.elem_types.into_iter().map(|t| t.ty.into()).collect()) @@ -127,7 +144,21 @@ impl Debug for Ty { } f.finish() } - Ty::Named(name) => write!(f, "{}", name), + Ty::Named { name, params } => { + write!(f, "{}", name)?; + + if !params.is_empty() { + write!(f, "<")?; + for (i, p) in params.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{:?}", p)?; + } + write!(f, ">")?; + } + Ok(()) + } Ty::Fn(fun) => write!(f, "{:?}", fun), Ty::Ctor(ctor) => write!(f, "new {:?}", ctor), Ty::Lit(members) => f.debug_set().entries(members).finish(), From c9c9482d6718bdc907004f88a7e828b4a7236be6 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 17:17:51 -0700 Subject: [PATCH 31/41] [ts-bindgen] add golden file tests, add rustfmt to codegen --- dom/ts-bindgen/Cargo.toml | 5 ++++- dom/ts-bindgen/src/lib.rs | 31 +++++++++++++++++++++++++++---- dom/ts-bindgen/tests/goldens.rs | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 dom/ts-bindgen/tests/goldens.rs diff --git a/dom/ts-bindgen/Cargo.toml b/dom/ts-bindgen/Cargo.toml index 4e528752e..18b865b85 100644 --- a/dom/ts-bindgen/Cargo.toml +++ b/dom/ts-bindgen/Cargo.toml @@ -9,4 +9,7 @@ quote = "1" swc_common = { version = "0.10.1", features = [ "tty-emitter" ] } swc_ecma_ast = "0.30.0" swc_ecma_parser = "0.36.2" -thiserror = "1.0.20" \ No newline at end of file +thiserror = "1.0.20" + +[dev-dependencies] +pretty_assertions = "0.6.1" \ No newline at end of file diff --git a/dom/ts-bindgen/src/lib.rs b/dom/ts-bindgen/src/lib.rs index d0da35800..eae10e184 100644 --- a/dom/ts-bindgen/src/lib.rs +++ b/dom/ts-bindgen/src/lib.rs @@ -1,5 +1,10 @@ use quote::ToTokens; -use std::{env, fs, path::Path}; +use std::{ + env, fs, + io::{prelude::*, Result as IoResult}, + path::Path, + process::{Command, Stdio}, +}; pub mod error; pub mod typescript; @@ -40,11 +45,29 @@ pub fn d_ts_buildscript( println!("cargo:rerun-if-changed={}", input_path.display()); let input = fs::read_to_string(input_path).map_err(BindingError::ReadInputFile)?; + let contents = make_bindings(&input)?; + fs::write(output_path, contents).map_err(BindingError::WriteOutFile)?; + Ok(()) +} +/// Parses `input` as a typescript definitions module and generates a module of +/// Rust bindings to it, returning the generated Rust code as a string. +pub fn make_bindings(input: &str) -> Result { let defs: TsModule = input.parse()?; let imports = defs.import_with_wasm_bindgen()?; - let contents = imports.to_token_stream().to_string(); + let output = imports.to_token_stream().to_string(); + if let Ok(formatted) = rustfmt(&output) { Ok(formatted) } else { Ok(output) } +} - fs::write(output_path, contents).map_err(BindingError::WriteOutFile)?; - Ok(()) +fn rustfmt(code: &str) -> IoResult { + let mut cmd = Command::new("rustfmt").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; + let mut stdin = cmd.stdin.take().unwrap(); + stdin.write_all(code.as_bytes())?; + + let output = cmd.wait_with_output()?; + if !output.status.success() { + Err(std::io::Error::new(std::io::ErrorKind::Other, "rustfmt command failed")) + } else { + Ok(String::from_utf8(output.stdout).expect("rustfmt always returns utf8")) + } } diff --git a/dom/ts-bindgen/tests/goldens.rs b/dom/ts-bindgen/tests/goldens.rs new file mode 100644 index 000000000..9943f1b8e --- /dev/null +++ b/dom/ts-bindgen/tests/goldens.rs @@ -0,0 +1,22 @@ +use pretty_assertions::assert_eq; +use std::path::Path; +use ts_bindgen::make_bindings; + +const GOLDENS_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/goldens/"); + +macro_rules! golden_test { + ($name:ident) => { + #[test] + fn $name() { + let goldens = Path::new(GOLDENS_DIR); + let input_path = goldens.join(concat!(stringify!($name), ".d.ts")); + let expect_path = goldens.join(concat!(stringify!($name), ".rs")); + + let input = std::fs::read_to_string(input_path).expect("reading test input"); + let expected = std::fs::read_to_string(expect_path).expect("reading expected output"); + + let actual = make_bindings(&input).expect("generating bindings"); + assert_eq!(actual, expected); + } + }; +} From aa2c957e2a95c1aa70a5ccb68681c6090e5cd5c3 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 17:49:12 -0700 Subject: [PATCH 32/41] [ts-bindgen] align debug output with source language --- dom/ts-bindgen/src/typescript/ty.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 4522e88b9..46e7c04b2 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -124,14 +124,14 @@ impl From for Ty { impl Debug for Ty { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { - Ty::Any => write!(f, "Any"), + Ty::Any => write!(f, "any"), Ty::Unknown => write!(f, "Unknown"), - Ty::Number => write!(f, "Number"), + Ty::Number => write!(f, "number"), Ty::Object => write!(f, "Object"), - Ty::Boolean => write!(f, "Boolean"), + Ty::Boolean => write!(f, "boolean"), Ty::BigInt => write!(f, "BigInt"), - Ty::String => write!(f, "String"), - Ty::Symbol => write!(f, "Symbol"), + Ty::String => write!(f, "string"), + Ty::Symbol => write!(f, "symbol"), Ty::Void => write!(f, "Void"), Ty::Undefined => write!(f, "undefined"), Ty::Null => write!(f, "null"), @@ -159,8 +159,7 @@ impl Debug for Ty { } Ok(()) } - Ty::Fn(fun) => write!(f, "{:?}", fun), - Ty::Ctor(ctor) => write!(f, "new {:?}", ctor), + Ty::Fn(fun) | Ty::Ctor(fun) => write!(f, "{:?}", fun), Ty::Lit(members) => f.debug_set().entries(members).finish(), Ty::Union(members) => { let mut tup = f.debug_tuple("∪"); From 883abfc8fdf41e0aefac5441d0622d24d6dadd03 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 17:50:41 -0700 Subject: [PATCH 33/41] [ts-bindgen] make sure golden rust files build --- dom/ts-bindgen/tests/goldens.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/dom/ts-bindgen/tests/goldens.rs b/dom/ts-bindgen/tests/goldens.rs index 9943f1b8e..42567fbc2 100644 --- a/dom/ts-bindgen/tests/goldens.rs +++ b/dom/ts-bindgen/tests/goldens.rs @@ -1,16 +1,21 @@ use pretty_assertions::assert_eq; -use std::path::Path; use ts_bindgen::make_bindings; -const GOLDENS_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/goldens/"); +macro_rules! golden { + ($($file:expr),+) => { + concat!(env!("CARGO_MANIFEST_DIR"), "/tests/goldens/", $($file),+) + }; +} macro_rules! golden_test { ($name:ident) => { #[test] fn $name() { - let goldens = Path::new(GOLDENS_DIR); - let input_path = goldens.join(concat!(stringify!($name), ".d.ts")); - let expect_path = goldens.join(concat!(stringify!($name), ".rs")); + let input_path = golden!(stringify!($name), ".d.ts"); + let expect_path = golden!(stringify!($name), ".rs"); + mod make_sure_expected_output_builds { + include!(golden!(stringify!($name), ".rs")); + } let input = std::fs::read_to_string(input_path).expect("reading test input"); let expected = std::fs::read_to_string(expect_path).expect("reading expected output"); From 38d407b0c79f38c4ab9478668be1ac32572eb01a Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sat, 5 Sep 2020 18:21:45 -0700 Subject: [PATCH 34/41] [ts-bindgen] add first golden test (failing) --- dom/ts-bindgen/Cargo.toml | 3 ++- dom/ts-bindgen/tests/goldens.rs | 9 ++++++++- dom/ts-bindgen/tests/goldens/bare_function.d.ts | 1 + dom/ts-bindgen/tests/goldens/bare_function.rs | 9 +++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 dom/ts-bindgen/tests/goldens/bare_function.d.ts create mode 100644 dom/ts-bindgen/tests/goldens/bare_function.rs diff --git a/dom/ts-bindgen/Cargo.toml b/dom/ts-bindgen/Cargo.toml index 18b865b85..5085624f3 100644 --- a/dom/ts-bindgen/Cargo.toml +++ b/dom/ts-bindgen/Cargo.toml @@ -12,4 +12,5 @@ swc_ecma_parser = "0.36.2" thiserror = "1.0.20" [dev-dependencies] -pretty_assertions = "0.6.1" \ No newline at end of file +pretty_assertions = "0.6.1" +wasm-bindgen = "0.2.67" \ No newline at end of file diff --git a/dom/ts-bindgen/tests/goldens.rs b/dom/ts-bindgen/tests/goldens.rs index 42567fbc2..9bfe11d73 100644 --- a/dom/ts-bindgen/tests/goldens.rs +++ b/dom/ts-bindgen/tests/goldens.rs @@ -18,10 +18,17 @@ macro_rules! golden_test { } let input = std::fs::read_to_string(input_path).expect("reading test input"); - let expected = std::fs::read_to_string(expect_path).expect("reading expected output"); + let expected = std::fs::read_to_string(expect_path) + .expect("reading expected output") + .split("// @@ end-expected @@ //") + .next() + .unwrap() + .to_string(); let actual = make_bindings(&input).expect("generating bindings"); assert_eq!(actual, expected); } }; } + +golden_test!(bare_function); diff --git a/dom/ts-bindgen/tests/goldens/bare_function.d.ts b/dom/ts-bindgen/tests/goldens/bare_function.d.ts new file mode 100644 index 000000000..c877984d2 --- /dev/null +++ b/dom/ts-bindgen/tests/goldens/bare_function.d.ts @@ -0,0 +1 @@ +export function bare(); \ No newline at end of file diff --git a/dom/ts-bindgen/tests/goldens/bare_function.rs b/dom/ts-bindgen/tests/goldens/bare_function.rs new file mode 100644 index 000000000..31ce6cb50 --- /dev/null +++ b/dom/ts-bindgen/tests/goldens/bare_function.rs @@ -0,0 +1,9 @@ +use wasm_bindgen::prelude::*; +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen] + pub fn bare(); +} +// @@ end-expected @@ // + +// TODO write tests that make sure we can use the function? From 50b9c6405b4fa4ae78a563f0e71805c39f31f2dd Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 6 Sep 2020 08:36:09 -0700 Subject: [PATCH 35/41] [ts-bindgen] initial totokens impls delete's the wasm module, we'll add that ir when we need it --- dom/ts-bindgen/src/lib.rs | 14 +++++---- dom/ts-bindgen/src/typescript/class.rs | 5 +++ dom/ts-bindgen/src/typescript/func.rs | 20 ++++++++++++ dom/ts-bindgen/src/typescript/module.rs | 42 ++++++++++++++++++++++--- dom/ts-bindgen/src/typescript/name.rs | 26 +++++++++++++++ dom/ts-bindgen/src/typescript/param.rs | 8 +++++ dom/ts-bindgen/src/typescript/ty.rs | 8 +++++ dom/ts-bindgen/src/wasm.rs | 11 ------- 8 files changed, 112 insertions(+), 22 deletions(-) delete mode 100644 dom/ts-bindgen/src/wasm.rs diff --git a/dom/ts-bindgen/src/lib.rs b/dom/ts-bindgen/src/lib.rs index eae10e184..b5a408120 100644 --- a/dom/ts-bindgen/src/lib.rs +++ b/dom/ts-bindgen/src/lib.rs @@ -1,4 +1,4 @@ -use quote::ToTokens; +use quote::quote; use std::{ env, fs, io::{prelude::*, Result as IoResult}, @@ -8,7 +8,6 @@ use std::{ pub mod error; pub mod typescript; -pub mod wasm; use error::BindingError; use typescript::TsModule; @@ -46,6 +45,7 @@ pub fn d_ts_buildscript( println!("cargo:rerun-if-changed={}", input_path.display()); let input = fs::read_to_string(input_path).map_err(BindingError::ReadInputFile)?; let contents = make_bindings(&input)?; + // TODO add header explaining generated code, hash of index.d.ts fs::write(output_path, contents).map_err(BindingError::WriteOutFile)?; Ok(()) } @@ -54,15 +54,17 @@ pub fn d_ts_buildscript( /// Rust bindings to it, returning the generated Rust code as a string. pub fn make_bindings(input: &str) -> Result { let defs: TsModule = input.parse()?; - let imports = defs.import_with_wasm_bindgen()?; - let output = imports.to_token_stream().to_string(); + let output = quote! { + use wasm_bindgen::prelude::*; + #defs + } + .to_string(); if let Ok(formatted) = rustfmt(&output) { Ok(formatted) } else { Ok(output) } } fn rustfmt(code: &str) -> IoResult { let mut cmd = Command::new("rustfmt").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; - let mut stdin = cmd.stdin.take().unwrap(); - stdin.write_all(code.as_bytes())?; + cmd.stdin.as_mut().unwrap().write_all(code.as_bytes())?; let output = cmd.wait_with_output()?; if !output.status.success() { diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index 6ce22369a..7e67c1e67 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -1,3 +1,4 @@ +use proc_macro2::TokenStream; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -73,6 +74,10 @@ impl Class { }; self.properties.insert(name, prop.type_ann.map(Ty::from).unwrap_or(Ty::Any)); } + + pub fn to_tokens_under_name(&self, _name: &Name, _tokens: &mut TokenStream) { + todo!("add class to tokens") + } } impl Debug for Class { diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index e5aee3d0e..b816a5298 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -1,3 +1,5 @@ +use proc_macro2::TokenStream; +use quote::quote; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -35,6 +37,24 @@ impl Func { returns: Some(Ty::named(name)), } } + + fn bindgen_attrs(&self) -> TokenStream { + quote! { + // TODO function import attributes + } + } + + pub fn to_tokens_under_name(&self, name: &Name, tokens: &mut TokenStream) { + let ret = if let Some(ret) = &self.returns { Some(quote!(-> #ret)) } else { None }; + let params = &self.params; + + let attrs = self.bindgen_attrs(); + + tokens.extend(quote! { + #[wasm_bindgen #attrs] + pub fn #name(#(#params),*) #ret; + }) + } } impl From for Func { diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index f230be8a6..9fc934519 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -1,4 +1,5 @@ -use crate::{error::TypescriptError, wasm::WasmBindgenImport}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -11,12 +12,14 @@ use swc_ecma_ast::{ use super::{class::Class, enums::Enum, func::Func, interface::Interface, name::Name, ty::Ty}; pub struct TsModule { - variables: BTreeMap, aliases: BTreeMap, enums: BTreeMap, - classes: BTreeMap, interfaces: BTreeMap, + + classes: BTreeMap, + variables: BTreeMap, functions: BTreeMap, + children: BTreeMap, } @@ -117,8 +120,8 @@ impl TsModule { } } - pub fn import_with_wasm_bindgen(&self) -> Result { - todo!("{:?}", self) + fn to_tokens_under_path(&self, name: &Name, tokens: &mut TokenStream) { + tokens.extend(quote! { pub mod #name { #self } }) } } @@ -130,3 +133,32 @@ fn module_name(id: &TsModuleName) -> Name { .to_string() .into() } + +impl ToTokens for TsModule { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut inner_tokens = TokenStream::new(); + + // TODO typescript aliases, enums, interfaces(traits) + // TODO module variables + + for (name, class) in &self.classes { + class.to_tokens_under_name(name, &mut inner_tokens); + } + + for (name, function) in &self.functions { + function.to_tokens_under_name(name, &mut inner_tokens); + } + + for (name, module) in &self.children { + // TODO pass the parent path through somehow + module.to_tokens_under_path(name, &mut inner_tokens); + } + + tokens.extend(quote! { + #[wasm_bindgen] // TODO module import path + extern "C" { + #inner_tokens + } + }); + } +} diff --git a/dom/ts-bindgen/src/typescript/name.rs b/dom/ts-bindgen/src/typescript/name.rs index 23bbccb4e..e6ed22d6b 100644 --- a/dom/ts-bindgen/src/typescript/name.rs +++ b/dom/ts-bindgen/src/typescript/name.rs @@ -1,12 +1,27 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{quote, ToTokens}; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use swc_ecma_ast::TsEntityName; #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Name { + // TODO preserve span from TS file segments: Vec, dotted: String, } +impl Name { + pub fn dot(&self, rhs: &Name) -> Self { + let mut segments = self.segments.clone(); + segments.extend(rhs.segments.clone()); + Self::from(segments) + } + + pub fn terminal(&self) -> &str { + self.segments.last().unwrap() + } +} + impl From for Name { fn from(dotted: String) -> Self { let segments = dotted.split(".").map(ToString::to_string).collect(); @@ -57,3 +72,14 @@ impl Display for Name { f.write_str(&self.dotted) } } + +impl ToTokens for Name { + fn to_tokens(&self, tokens: &mut TokenStream) { + let segments: Vec<_> = + self.segments.iter().map(|s| Ident::new(s, Span::call_site())).collect(); + + tokens.extend(quote! { + #(#segments).* + }) + } +} diff --git a/dom/ts-bindgen/src/typescript/param.rs b/dom/ts-bindgen/src/typescript/param.rs index 42ab4523e..cd67eb83b 100644 --- a/dom/ts-bindgen/src/typescript/param.rs +++ b/dom/ts-bindgen/src/typescript/param.rs @@ -1,3 +1,5 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; use std::fmt::{Debug, Formatter, Result as FmtResult}; use swc_ecma_ast::{Param, Pat, TsFnParam}; @@ -55,3 +57,9 @@ impl Debug for TsParam { write!(f, "{}{}{}: {:?}", rest, &self.name, optional, &self.ty) } } + +impl ToTokens for TsParam { + fn to_tokens(&self, tokens: &mut TokenStream) { + // TODO + } +} diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index 46e7c04b2..f1c2a7353 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,5 +1,7 @@ #![allow(unused)] +use proc_macro2::TokenStream; +use quote::ToTokens; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -179,6 +181,12 @@ impl Debug for Ty { } } +impl ToTokens for Ty { + fn to_tokens(&self, tokens: &mut TokenStream) { + // TODO + } +} + #[derive(Clone)] pub struct TyParam { constraint: Option, diff --git a/dom/ts-bindgen/src/wasm.rs b/dom/ts-bindgen/src/wasm.rs deleted file mode 100644 index b87154f98..000000000 --- a/dom/ts-bindgen/src/wasm.rs +++ /dev/null @@ -1,11 +0,0 @@ -use proc_macro2::TokenStream; -use quote::ToTokens; - -#[derive(Debug)] -pub struct WasmBindgenImport {} - -impl ToTokens for WasmBindgenImport { - fn to_tokens(&self, _ts: &mut TokenStream) { - todo!() - } -} From 691cb5f54b3eb4a3011fea55644a4cf4851df5b4 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 6 Sep 2020 08:47:14 -0700 Subject: [PATCH 36/41] [ts-bindgen] get modules compiling ok --- dom/ts-bindgen/src/typescript/module.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index 9fc934519..a5dc7b681 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -121,7 +121,13 @@ impl TsModule { } fn to_tokens_under_path(&self, name: &Name, tokens: &mut TokenStream) { - tokens.extend(quote! { pub mod #name { #self } }) + tokens.extend(quote! { + pub mod #name { + use super::*; + use wasm_bindgen::prelude::*; + #self + } + }) } } @@ -136,29 +142,31 @@ fn module_name(id: &TsModuleName) -> Name { impl ToTokens for TsModule { fn to_tokens(&self, tokens: &mut TokenStream) { - let mut inner_tokens = TokenStream::new(); + let mut own_tokens = TokenStream::new(); // TODO typescript aliases, enums, interfaces(traits) // TODO module variables for (name, class) in &self.classes { - class.to_tokens_under_name(name, &mut inner_tokens); + class.to_tokens_under_name(name, &mut own_tokens); } for (name, function) in &self.functions { - function.to_tokens_under_name(name, &mut inner_tokens); + function.to_tokens_under_name(name, &mut own_tokens); } + let mut child_tokens = TokenStream::new(); for (name, module) in &self.children { // TODO pass the parent path through somehow - module.to_tokens_under_path(name, &mut inner_tokens); + module.to_tokens_under_path(name, &mut child_tokens); } tokens.extend(quote! { #[wasm_bindgen] // TODO module import path extern "C" { - #inner_tokens + #own_tokens } + #child_tokens }); } } From db7f91c8ef822968aa77c7b4b631a074d8329ffa Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 7 Sep 2020 08:09:52 -0700 Subject: [PATCH 37/41] [project] add list of crates to repo readme --- CONTRIBUTING.md | 1 + README.md | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d505e0bfd..10c7e6cfe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -99,5 +99,6 @@ Things to update: * `.cargo/config` * `.github/workflows/main.yml` * `index.html` +* `README.md` (Dependabot discovers the workspace members from the root manifest.) diff --git a/README.md b/README.md index f34883cf6..90e4b361d 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,35 @@ For more information about the moxie project, see the [website](https://moxie.rs). +## Crates in this repository + +### moxie-dom and other Web/HTML/JS crates + +[`moxie-dom`](./dom) offers APIs for incrementally constructing HTML in the browser and elsewhere. +See [examples](./dom/examples) for demos, live versions of which are available on +[the project's website](https://moxie.rs/#web). + +[`augdom`](./dom/augdom) wraps the web's [DOM] API and augments it with non-Web polyfills for e.g. +server-side rendering. + +[`prettiest`](./dom/prettiest) is a Rust pretty-printer for JavaScript values. + +[`raf`](./dom/raf) is a runloop scheduler built with [`requestAnimationFrame`]. + +### Platform-agnostic crates + +[`moxie`](./src) is an [incremental] runtime offering caching and "reactive" state management. + +[`dyn-cache`](./dyn-cache) offers generational caches for arbitrary Rust types, allowing a single +database struct to be used for any number of static or dynamic queries. + +[`illicit`](./illicit) offers thread-local type-indexed implicit context singletons. + +[`topo`](./topo) creates reproducible identifiers for locations in the runtime callgraph. Used to +generate query scopes for `dyn-cache` storage. + +[`mox`](/.mox) implements an XML-like syntax for Rust builders inspired by [JSX]. + ## Contributing and Code of Conduct See [CONTRIBUTING.md](CONTRIBUTING.md) for overall contributing info and [CONDUCT.md](CODE_OF_CONDUCT.md) @@ -24,3 +53,8 @@ Licensed under either of * [MIT license](LICENSE-MIT) at your option. + +[DOM]: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model +[`requestAnimationFrame`]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame +[incremental]: http://adapton.org/ +[JSX]: https://facebook.github.io/jsx/ From 3ef10d0e634a1d148f8639ffb29e45d09a49dee4 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 7 Sep 2020 08:15:09 -0700 Subject: [PATCH 38/41] [honk][vscode] switch the boilerplate to a tree data provider --- .cargo/config.toml | 11 +++++ .vscode/tasks.json | 35 ++++++++------ Cargo.toml | 2 + honk/editors/vscode/Cargo.toml | 23 +++++++++ honk/editors/vscode/extension.js | 9 ++-- honk/editors/vscode/package.json | 25 +++++++--- honk/editors/vscode/static/icon.svg | 75 +++++++++++++++++++++++++++++ 7 files changed, 154 insertions(+), 26 deletions(-) create mode 100644 honk/editors/vscode/Cargo.toml create mode 100644 honk/editors/vscode/static/icon.svg diff --git a/.cargo/config.toml b/.cargo/config.toml index d974d2bc7..ddee2b8dd 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -104,6 +104,17 @@ clippy-dom = """clippy --package todomvc-moxie """ +#################################################################################################### +# honk, the awful replacement for ofl + +honk-flow = """ +watch --clear + -x test-ts-bindgen + -x build-honk-vscode +""" + +build-honk-vscode = "wa-pack-build honk/editors/vscode" + #################################################################################################### # ofl diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2db8805c8..57923f689 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,15 +4,12 @@ "version": "2.0.0", "tasks": [ { - "label": "core crates", + "label": "core", "type": "shell", "presentation": { "group": "main", "panel": "dedicated" }, - "runOptions": { - "runOn": "folderOpen" - }, "isBackground": true, "command": "cargo", "args": [ @@ -23,15 +20,12 @@ ] }, { - "label": "dom crates", + "label": "dom", "type": "shell", "presentation": { "group": "main", "panel": "dedicated" }, - "runOptions": { - "runOn": "folderOpen" - }, "isBackground": true, "command": "cargo", "args": [ @@ -42,7 +36,23 @@ ] }, { - "label": "project website", + "label": "honk", + "type": "shell", + "presentation": { + "group": "main", + "panel": "dedicated" + }, + "isBackground": true, + "command": "cargo", + "args": [ + "honk-flow" + ], + "problemMatcher": [ + "$rustc-watch" + ] + }, + { + "label": "website", "type": "shell", "presentation": { "group": "tools", @@ -61,7 +71,7 @@ ] }, { - "label": "project server", + "label": "server", "type": "shell", "presentation": { "group": "tools", @@ -78,7 +88,7 @@ "problemMatcher": [] }, { - "label": "ofl crates", + "label": "ofl", "type": "shell", "presentation": { "group": "tools", @@ -126,9 +136,6 @@ "group": "tools", "panel": "dedicated" }, - "runOptions": { - "runOn": "folderOpen" - }, "isBackground": true, "command": "npx", "args": [ diff --git a/Cargo.toml b/Cargo.toml index ecc788172..ebbd1b06b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,8 @@ members = [ "dom/ts-bindgen", "dyn-cache", "honk", + "honk/editors/vscode", + "honk/editors/vscode/sys", "illicit", "illicit/macro", "mox", diff --git a/honk/editors/vscode/Cargo.toml b/honk/editors/vscode/Cargo.toml new file mode 100644 index 000000000..0204f6dc8 --- /dev/null +++ b/honk/editors/vscode/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "honk-vscode" +description = "an awful billed system's vscode extension" +version = "0.1.0-pre" +publish = false +edition = "2018" +license-file = "../../../../LICENSE-MIT" +repository = "https://github.com/anp/moxie.git" + +[lib] +crate-type = [ "cdylib" ] + +[dependencies] +code-sys = { path = "sys", version = "0.1.0-pre" } +console_error_panic_hook = "0.1.6" +moxie-dom = { path = "../../../dom" } +tracing = { version = "^0.1", features = [ "log" ] } +tracing-wasm = "0.1.0" +wasm-bindgen = "0.2" + +[dev-dependencies] +pretty_assertions = "0.6" +wasm-bindgen-test = "0.3" diff --git a/honk/editors/vscode/extension.js b/honk/editors/vscode/extension.js index e6db8d074..25147140f 100644 --- a/honk/editors/vscode/extension.js +++ b/honk/editors/vscode/extension.js @@ -3,14 +3,13 @@ const vscode = require('vscode'); function activate(context) { // only executed once when extension is activated console.log('honkity honk'); + vscode.window.showInformationMessage('honk starting...'); + // const focusProvider = new FocusProvider(vscode.workspace.rootPath); + // vscode.window.registerTreeDataProvider('focus', focusProvider); // TODO make this a panel thingy - let disposable = vscode.commands.registerCommand('honk.boot', function () { - // executed every time command is executed - vscode.window.showInformationMessage('honk'); - }); - context.subscriptions.push(disposable); + vscode.window.showInformationMessage('honk started'); } exports.activate = activate; diff --git a/honk/editors/vscode/package.json b/honk/editors/vscode/package.json index c5570c747..348ddd588 100644 --- a/honk/editors/vscode/package.json +++ b/honk/editors/vscode/package.json @@ -10,16 +10,27 @@ "Other" ], "activationEvents": [ - "onCommand:honk.boot" + "onView:focus" ], "main": "./extension.js", "contributes": { - "commands": [ - { - "command": "honk.boot", - "title": "honk" - } - ] + "viewsContainers": { + "activitybar": [ + { + "id": "honk", + "title": "honk", + "icon": "static/icon.svg" + } + ] + }, + "views": { + "honk": [ + { + "id": "focus", + "name": "focused items" + } + ] + } }, "scripts": { "lint": "eslint .", diff --git a/honk/editors/vscode/static/icon.svg b/honk/editors/vscode/static/icon.svg new file mode 100644 index 000000000..a001b8469 --- /dev/null +++ b/honk/editors/vscode/static/icon.svg @@ -0,0 +1,75 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + From 4b3eb4cf8dd5a2a768db5911275d98bc7d322870 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 7 Sep 2020 08:22:59 -0700 Subject: [PATCH 39/41] [ts-bindgen] start switching strategies to generating webidl --- dom/ts-bindgen/Cargo.toml | 4 +-- dom/ts-bindgen/src/error.rs | 3 ++ dom/ts-bindgen/src/lib.rs | 11 +++---- dom/ts-bindgen/src/typescript/class.rs | 5 --- dom/ts-bindgen/src/typescript/func.rs | 20 ------------ dom/ts-bindgen/src/typescript/module.rs | 43 ++----------------------- dom/ts-bindgen/src/typescript/name.rs | 13 -------- dom/ts-bindgen/src/typescript/param.rs | 8 ----- dom/ts-bindgen/src/typescript/ty.rs | 8 ----- dom/ts-bindgen/tests/goldens.rs | 3 ++ 10 files changed, 15 insertions(+), 103 deletions(-) diff --git a/dom/ts-bindgen/Cargo.toml b/dom/ts-bindgen/Cargo.toml index 5085624f3..a9feb50c2 100644 --- a/dom/ts-bindgen/Cargo.toml +++ b/dom/ts-bindgen/Cargo.toml @@ -4,12 +4,12 @@ version = "0.1.0" edition = "2018" [dependencies] -proc-macro2 = "1" -quote = "1" +anyhow = "1" swc_common = { version = "0.10.1", features = [ "tty-emitter" ] } swc_ecma_ast = "0.30.0" swc_ecma_parser = "0.36.2" thiserror = "1.0.20" +wasm-bindgen-webidl = "0.2.67" [dev-dependencies] pretty_assertions = "0.6.1" diff --git a/dom/ts-bindgen/src/error.rs b/dom/ts-bindgen/src/error.rs index 81b019c39..bf69a4804 100644 --- a/dom/ts-bindgen/src/error.rs +++ b/dom/ts-bindgen/src/error.rs @@ -18,6 +18,9 @@ pub enum BindingError { #[from] source: TypescriptError, }, + + #[error("generating wasm bindgen from webidl failed")] + WasmBindgen(#[source] anyhow::Error), } #[derive(Debug, Error)] diff --git a/dom/ts-bindgen/src/lib.rs b/dom/ts-bindgen/src/lib.rs index b5a408120..66deb45fa 100644 --- a/dom/ts-bindgen/src/lib.rs +++ b/dom/ts-bindgen/src/lib.rs @@ -1,4 +1,3 @@ -use quote::quote; use std::{ env, fs, io::{prelude::*, Result as IoResult}, @@ -54,11 +53,11 @@ pub fn d_ts_buildscript( /// Rust bindings to it, returning the generated Rust code as a string. pub fn make_bindings(input: &str) -> Result { let defs: TsModule = input.parse()?; - let output = quote! { - use wasm_bindgen::prelude::*; - #defs - } - .to_string(); + let defs = defs.as_webidl(); + let features = + wasm_bindgen_webidl::compile(&defs, "", wasm_bindgen_webidl::Options { features: false }) + .map_err(BindingError::WasmBindgen)?; + let output = features.into_iter().map(|(_, f)| f.code).collect::>().join("\n"); if let Ok(formatted) = rustfmt(&output) { Ok(formatted) } else { Ok(output) } } diff --git a/dom/ts-bindgen/src/typescript/class.rs b/dom/ts-bindgen/src/typescript/class.rs index 7e67c1e67..6ce22369a 100644 --- a/dom/ts-bindgen/src/typescript/class.rs +++ b/dom/ts-bindgen/src/typescript/class.rs @@ -1,4 +1,3 @@ -use proc_macro2::TokenStream; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -74,10 +73,6 @@ impl Class { }; self.properties.insert(name, prop.type_ann.map(Ty::from).unwrap_or(Ty::Any)); } - - pub fn to_tokens_under_name(&self, _name: &Name, _tokens: &mut TokenStream) { - todo!("add class to tokens") - } } impl Debug for Class { diff --git a/dom/ts-bindgen/src/typescript/func.rs b/dom/ts-bindgen/src/typescript/func.rs index b816a5298..e5aee3d0e 100644 --- a/dom/ts-bindgen/src/typescript/func.rs +++ b/dom/ts-bindgen/src/typescript/func.rs @@ -1,5 +1,3 @@ -use proc_macro2::TokenStream; -use quote::quote; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -37,24 +35,6 @@ impl Func { returns: Some(Ty::named(name)), } } - - fn bindgen_attrs(&self) -> TokenStream { - quote! { - // TODO function import attributes - } - } - - pub fn to_tokens_under_name(&self, name: &Name, tokens: &mut TokenStream) { - let ret = if let Some(ret) = &self.returns { Some(quote!(-> #ret)) } else { None }; - let params = &self.params; - - let attrs = self.bindgen_attrs(); - - tokens.extend(quote! { - #[wasm_bindgen #attrs] - pub fn #name(#(#params),*) #ret; - }) - } } impl From for Func { diff --git a/dom/ts-bindgen/src/typescript/module.rs b/dom/ts-bindgen/src/typescript/module.rs index a5dc7b681..85c822625 100644 --- a/dom/ts-bindgen/src/typescript/module.rs +++ b/dom/ts-bindgen/src/typescript/module.rs @@ -1,5 +1,3 @@ -use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -120,14 +118,8 @@ impl TsModule { } } - fn to_tokens_under_path(&self, name: &Name, tokens: &mut TokenStream) { - tokens.extend(quote! { - pub mod #name { - use super::*; - use wasm_bindgen::prelude::*; - #self - } - }) + pub fn as_webidl(&self) -> String { + todo!() } } @@ -139,34 +131,3 @@ fn module_name(id: &TsModuleName) -> Name { .to_string() .into() } - -impl ToTokens for TsModule { - fn to_tokens(&self, tokens: &mut TokenStream) { - let mut own_tokens = TokenStream::new(); - - // TODO typescript aliases, enums, interfaces(traits) - // TODO module variables - - for (name, class) in &self.classes { - class.to_tokens_under_name(name, &mut own_tokens); - } - - for (name, function) in &self.functions { - function.to_tokens_under_name(name, &mut own_tokens); - } - - let mut child_tokens = TokenStream::new(); - for (name, module) in &self.children { - // TODO pass the parent path through somehow - module.to_tokens_under_path(name, &mut child_tokens); - } - - tokens.extend(quote! { - #[wasm_bindgen] // TODO module import path - extern "C" { - #own_tokens - } - #child_tokens - }); - } -} diff --git a/dom/ts-bindgen/src/typescript/name.rs b/dom/ts-bindgen/src/typescript/name.rs index e6ed22d6b..08600fb91 100644 --- a/dom/ts-bindgen/src/typescript/name.rs +++ b/dom/ts-bindgen/src/typescript/name.rs @@ -1,5 +1,3 @@ -use proc_macro2::{Ident, Span, TokenStream}; -use quote::{quote, ToTokens}; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use swc_ecma_ast::TsEntityName; @@ -72,14 +70,3 @@ impl Display for Name { f.write_str(&self.dotted) } } - -impl ToTokens for Name { - fn to_tokens(&self, tokens: &mut TokenStream) { - let segments: Vec<_> = - self.segments.iter().map(|s| Ident::new(s, Span::call_site())).collect(); - - tokens.extend(quote! { - #(#segments).* - }) - } -} diff --git a/dom/ts-bindgen/src/typescript/param.rs b/dom/ts-bindgen/src/typescript/param.rs index cd67eb83b..42ab4523e 100644 --- a/dom/ts-bindgen/src/typescript/param.rs +++ b/dom/ts-bindgen/src/typescript/param.rs @@ -1,5 +1,3 @@ -use proc_macro2::TokenStream; -use quote::ToTokens; use std::fmt::{Debug, Formatter, Result as FmtResult}; use swc_ecma_ast::{Param, Pat, TsFnParam}; @@ -57,9 +55,3 @@ impl Debug for TsParam { write!(f, "{}{}{}: {:?}", rest, &self.name, optional, &self.ty) } } - -impl ToTokens for TsParam { - fn to_tokens(&self, tokens: &mut TokenStream) { - // TODO - } -} diff --git a/dom/ts-bindgen/src/typescript/ty.rs b/dom/ts-bindgen/src/typescript/ty.rs index f1c2a7353..46e7c04b2 100644 --- a/dom/ts-bindgen/src/typescript/ty.rs +++ b/dom/ts-bindgen/src/typescript/ty.rs @@ -1,7 +1,5 @@ #![allow(unused)] -use proc_macro2::TokenStream; -use quote::ToTokens; use std::{ collections::BTreeMap, fmt::{Debug, Formatter, Result as FmtResult}, @@ -181,12 +179,6 @@ impl Debug for Ty { } } -impl ToTokens for Ty { - fn to_tokens(&self, tokens: &mut TokenStream) { - // TODO - } -} - #[derive(Clone)] pub struct TyParam { constraint: Option, diff --git a/dom/ts-bindgen/tests/goldens.rs b/dom/ts-bindgen/tests/goldens.rs index 9bfe11d73..dcbf517cc 100644 --- a/dom/ts-bindgen/tests/goldens.rs +++ b/dom/ts-bindgen/tests/goldens.rs @@ -26,6 +26,9 @@ macro_rules! golden_test { .to_string(); let actual = make_bindings(&input).expect("generating bindings"); + + // TODO use an env var to decide whether to assert or bless the generated + // binding assert_eq!(actual, expected); } }; From 54babe98f231ed3b8e0036c9e5367988858d5bcc Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 7 Sep 2020 08:24:36 -0700 Subject: [PATCH 40/41] [honk][vscode] initial code-sys crate (doesn't build) --- honk/editors/vscode/sys/@types/vscode/LICENSE | 21 + .../vscode/sys/@types/vscode/README.md | 16 + .../vscode/sys/@types/vscode/index.d.ts | 11687 ++++++++++++++++ .../vscode/sys/@types/vscode/package.json | 53 + honk/editors/vscode/sys/Cargo.toml | 20 + honk/editors/vscode/sys/build.rs | 3 + honk/editors/vscode/sys/src/lib.rs | 1 + 7 files changed, 11801 insertions(+) create mode 100644 honk/editors/vscode/sys/@types/vscode/LICENSE create mode 100644 honk/editors/vscode/sys/@types/vscode/README.md create mode 100644 honk/editors/vscode/sys/@types/vscode/index.d.ts create mode 100644 honk/editors/vscode/sys/@types/vscode/package.json create mode 100644 honk/editors/vscode/sys/Cargo.toml create mode 100644 honk/editors/vscode/sys/build.rs create mode 100644 honk/editors/vscode/sys/src/lib.rs diff --git a/honk/editors/vscode/sys/@types/vscode/LICENSE b/honk/editors/vscode/sys/@types/vscode/LICENSE new file mode 100644 index 000000000..9e841e7a2 --- /dev/null +++ b/honk/editors/vscode/sys/@types/vscode/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/honk/editors/vscode/sys/@types/vscode/README.md b/honk/editors/vscode/sys/@types/vscode/README.md new file mode 100644 index 000000000..46d52a0b8 --- /dev/null +++ b/honk/editors/vscode/sys/@types/vscode/README.md @@ -0,0 +1,16 @@ +# Installation +> `npm install --save @types/vscode` + +# Summary +This package contains type definitions for Visual Studio Code (https://github.com/microsoft/vscode). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/vscode. + +### Additional Details + * Last updated: Thu, 13 Aug 2020 19:51:51 GMT + * Dependencies: none + * Global values: none + +# Credits +These definitions were written by [Visual Studio Code Team, and Microsoft](https://github.com/Microsoft). diff --git a/honk/editors/vscode/sys/@types/vscode/index.d.ts b/honk/editors/vscode/sys/@types/vscode/index.d.ts new file mode 100644 index 000000000..160269c64 --- /dev/null +++ b/honk/editors/vscode/sys/@types/vscode/index.d.ts @@ -0,0 +1,11687 @@ +// Type definitions for Visual Studio Code 1.48 +// Project: https://github.com/microsoft/vscode +// Definitions by: Visual Studio Code Team, Microsoft +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * See https://github.com/Microsoft/vscode/blob/master/LICENSE.txt for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Type Definition for Visual Studio Code 1.48 Extension API + * See https://code.visualstudio.com/api for more information + */ + +declare module 'vscode' { + + /** + * The version of the editor. + */ + export const version: string; + + /** + * Represents a reference to a command. Provides a title which + * will be used to represent a command in the UI and, optionally, + * an array of arguments which will be passed to the command handler + * function when invoked. + */ + export interface Command { + /** + * Title of the command, like `save`. + */ + title: string; + + /** + * The identifier of the actual command handler. + * @see [commands.registerCommand](#commands.registerCommand). + */ + command: string; + + /** + * A tooltip for the command, when represented in the UI. + */ + tooltip?: string; + + /** + * Arguments that the command handler should be + * invoked with. + */ + arguments?: any[]; + } + + /** + * Represents a line of text, such as a line of source code. + * + * TextLine objects are __immutable__. When a [document](#TextDocument) changes, + * previously retrieved lines will not represent the latest state. + */ + export interface TextLine { + + /** + * The zero-based line number. + */ + readonly lineNumber: number; + + /** + * The text of this line without the line separator characters. + */ + readonly text: string; + + /** + * The range this line covers without the line separator characters. + */ + readonly range: Range; + + /** + * The range this line covers with the line separator characters. + */ + readonly rangeIncludingLineBreak: Range; + + /** + * The offset of the first character which is not a whitespace character as defined + * by `/\s/`. **Note** that if a line is all whitespace the length of the line is returned. + */ + readonly firstNonWhitespaceCharacterIndex: number; + + /** + * Whether this line is whitespace only, shorthand + * for [TextLine.firstNonWhitespaceCharacterIndex](#TextLine.firstNonWhitespaceCharacterIndex) === [TextLine.text.length](#TextLine.text). + */ + readonly isEmptyOrWhitespace: boolean; + } + + /** + * Represents a text document, such as a source file. Text documents have + * [lines](#TextLine) and knowledge about an underlying resource like a file. + */ + export interface TextDocument { + + /** + * The associated uri for this document. + * + * *Note* that most documents use the `file`-scheme, which means they are files on disk. However, **not** all documents are + * saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk. + * + * @see [FileSystemProvider](#FileSystemProvider) + * @see [TextDocumentContentProvider](#TextDocumentContentProvider) + */ + readonly uri: Uri; + + /** + * The file system path of the associated resource. Shorthand + * notation for [TextDocument.uri.fsPath](#TextDocument.uri). Independent of the uri scheme. + */ + readonly fileName: string; + + /** + * Is this document representing an untitled file which has never been saved yet. *Note* that + * this does not mean the document will be saved to disk, use [`uri.scheme`](#Uri.scheme) + * to figure out where a document will be [saved](#FileSystemProvider), e.g. `file`, `ftp` etc. + */ + readonly isUntitled: boolean; + + /** + * The identifier of the language associated with this document. + */ + readonly languageId: string; + + /** + * The version number of this document (it will strictly increase after each + * change, including undo/redo). + */ + readonly version: number; + + /** + * `true` if there are unpersisted changes. + */ + readonly isDirty: boolean; + + /** + * `true` if the document has been closed. A closed document isn't synchronized anymore + * and won't be re-used when the same resource is opened again. + */ + readonly isClosed: boolean; + + /** + * Save the underlying file. + * + * @return A promise that will resolve to true when the file + * has been saved. If the file was not dirty or the save failed, + * will return false. + */ + save(): Thenable; + + /** + * The [end of line](#EndOfLine) sequence that is predominately + * used in this document. + */ + readonly eol: EndOfLine; + + /** + * The number of lines in this document. + */ + readonly lineCount: number; + + /** + * Returns a text line denoted by the line number. Note + * that the returned object is *not* live and changes to the + * document are not reflected. + * + * @param line A line number in [0, lineCount). + * @return A [line](#TextLine). + */ + lineAt(line: number): TextLine; + + /** + * Returns a text line denoted by the position. Note + * that the returned object is *not* live and changes to the + * document are not reflected. + * + * The position will be [adjusted](#TextDocument.validatePosition). + * + * @see [TextDocument.lineAt](#TextDocument.lineAt) + * @param position A position. + * @return A [line](#TextLine). + */ + lineAt(position: Position): TextLine; + + /** + * Converts the position to a zero-based offset. + * + * The position will be [adjusted](#TextDocument.validatePosition). + * + * @param position A position. + * @return A valid zero-based offset. + */ + offsetAt(position: Position): number; + + /** + * Converts a zero-based offset to a position. + * + * @param offset A zero-based offset. + * @return A valid [position](#Position). + */ + positionAt(offset: number): Position; + + /** + * Get the text of this document. A substring can be retrieved by providing + * a range. The range will be [adjusted](#TextDocument.validateRange). + * + * @param range Include only the text included by the range. + * @return The text inside the provided range or the entire text. + */ + getText(range?: Range): string; + + /** + * Get a word-range at the given position. By default words are defined by + * common separators, like space, -, _, etc. In addition, per language custom + * [word definitions](#LanguageConfiguration.wordPattern) can be defined. It + * is also possible to provide a custom regular expression. + * + * * *Note 1:* A custom regular expression must not match the empty string and + * if it does, it will be ignored. + * * *Note 2:* A custom regular expression will fail to match multiline strings + * and in the name of speed regular expressions should not match words with + * spaces. Use [`TextLine.text`](#TextLine.text) for more complex, non-wordy, scenarios. + * + * The position will be [adjusted](#TextDocument.validatePosition). + * + * @param position A position. + * @param regex Optional regular expression that describes what a word is. + * @return A range spanning a word, or `undefined`. + */ + getWordRangeAtPosition(position: Position, regex?: RegExp): Range | undefined; + + /** + * Ensure a range is completely contained in this document. + * + * @param range A range. + * @return The given range or a new, adjusted range. + */ + validateRange(range: Range): Range; + + /** + * Ensure a position is contained in the range of this document. + * + * @param position A position. + * @return The given position or a new, adjusted position. + */ + validatePosition(position: Position): Position; + } + + /** + * Represents a line and character position, such as + * the position of the cursor. + * + * Position objects are __immutable__. Use the [with](#Position.with) or + * [translate](#Position.translate) methods to derive new positions + * from an existing position. + */ + export class Position { + + /** + * The zero-based line value. + */ + readonly line: number; + + /** + * The zero-based character value. + */ + readonly character: number; + + /** + * @param line A zero-based line value. + * @param character A zero-based character value. + */ + constructor(line: number, character: number); + + /** + * Check if this position is before `other`. + * + * @param other A position. + * @return `true` if position is on a smaller line + * or on the same line on a smaller character. + */ + isBefore(other: Position): boolean; + + /** + * Check if this position is before or equal to `other`. + * + * @param other A position. + * @return `true` if position is on a smaller line + * or on the same line on a smaller or equal character. + */ + isBeforeOrEqual(other: Position): boolean; + + /** + * Check if this position is after `other`. + * + * @param other A position. + * @return `true` if position is on a greater line + * or on the same line on a greater character. + */ + isAfter(other: Position): boolean; + + /** + * Check if this position is after or equal to `other`. + * + * @param other A position. + * @return `true` if position is on a greater line + * or on the same line on a greater or equal character. + */ + isAfterOrEqual(other: Position): boolean; + + /** + * Check if this position is equal to `other`. + * + * @param other A position. + * @return `true` if the line and character of the given position are equal to + * the line and character of this position. + */ + isEqual(other: Position): boolean; + + /** + * Compare this to `other`. + * + * @param other A position. + * @return A number smaller than zero if this position is before the given position, + * a number greater than zero if this position is after the given position, or zero when + * this and the given position are equal. + */ + compareTo(other: Position): number; + + /** + * Create a new position relative to this position. + * + * @param lineDelta Delta value for the line value, default is `0`. + * @param characterDelta Delta value for the character value, default is `0`. + * @return A position which line and character is the sum of the current line and + * character and the corresponding deltas. + */ + translate(lineDelta?: number, characterDelta?: number): Position; + + /** + * Derived a new position relative to this position. + * + * @param change An object that describes a delta to this position. + * @return A position that reflects the given delta. Will return `this` position if the change + * is not changing anything. + */ + translate(change: { lineDelta?: number; characterDelta?: number; }): Position; + + /** + * Create a new position derived from this position. + * + * @param line Value that should be used as line value, default is the [existing value](#Position.line) + * @param character Value that should be used as character value, default is the [existing value](#Position.character) + * @return A position where line and character are replaced by the given values. + */ + with(line?: number, character?: number): Position; + + /** + * Derived a new position from this position. + * + * @param change An object that describes a change to this position. + * @return A position that reflects the given change. Will return `this` position if the change + * is not changing anything. + */ + with(change: { line?: number; character?: number; }): Position; + } + + /** + * A range represents an ordered pair of two positions. + * It is guaranteed that [start](#Range.start).isBeforeOrEqual([end](#Range.end)) + * + * Range objects are __immutable__. Use the [with](#Range.with), + * [intersection](#Range.intersection), or [union](#Range.union) methods + * to derive new ranges from an existing range. + */ + export class Range { + + /** + * The start position. It is before or equal to [end](#Range.end). + */ + readonly start: Position; + + /** + * The end position. It is after or equal to [start](#Range.start). + */ + readonly end: Position; + + /** + * Create a new range from two positions. If `start` is not + * before or equal to `end`, the values will be swapped. + * + * @param start A position. + * @param end A position. + */ + constructor(start: Position, end: Position); + + /** + * Create a new range from number coordinates. It is a shorter equivalent of + * using `new Range(new Position(startLine, startCharacter), new Position(endLine, endCharacter))` + * + * @param startLine A zero-based line value. + * @param startCharacter A zero-based character value. + * @param endLine A zero-based line value. + * @param endCharacter A zero-based character value. + */ + constructor(startLine: number, startCharacter: number, endLine: number, endCharacter: number); + + /** + * `true` if `start` and `end` are equal. + */ + isEmpty: boolean; + + /** + * `true` if `start.line` and `end.line` are equal. + */ + isSingleLine: boolean; + + /** + * Check if a position or a range is contained in this range. + * + * @param positionOrRange A position or a range. + * @return `true` if the position or range is inside or equal + * to this range. + */ + contains(positionOrRange: Position | Range): boolean; + + /** + * Check if `other` equals this range. + * + * @param other A range. + * @return `true` when start and end are [equal](#Position.isEqual) to + * start and end of this range. + */ + isEqual(other: Range): boolean; + + /** + * Intersect `range` with this range and returns a new range or `undefined` + * if the ranges have no overlap. + * + * @param range A range. + * @return A range of the greater start and smaller end positions. Will + * return undefined when there is no overlap. + */ + intersection(range: Range): Range | undefined; + + /** + * Compute the union of `other` with this range. + * + * @param other A range. + * @return A range of smaller start position and the greater end position. + */ + union(other: Range): Range; + + /** + * Derived a new range from this range. + * + * @param start A position that should be used as start. The default value is the [current start](#Range.start). + * @param end A position that should be used as end. The default value is the [current end](#Range.end). + * @return A range derived from this range with the given start and end position. + * If start and end are not different `this` range will be returned. + */ + with(start?: Position, end?: Position): Range; + + /** + * Derived a new range from this range. + * + * @param change An object that describes a change to this range. + * @return A range that reflects the given change. Will return `this` range if the change + * is not changing anything. + */ + with(change: { start?: Position, end?: Position }): Range; + } + + /** + * Represents a text selection in an editor. + */ + export class Selection extends Range { + + /** + * The position at which the selection starts. + * This position might be before or after [active](#Selection.active). + */ + anchor: Position; + + /** + * The position of the cursor. + * This position might be before or after [anchor](#Selection.anchor). + */ + active: Position; + + /** + * Create a selection from two positions. + * + * @param anchor A position. + * @param active A position. + */ + constructor(anchor: Position, active: Position); + + /** + * Create a selection from four coordinates. + * + * @param anchorLine A zero-based line value. + * @param anchorCharacter A zero-based character value. + * @param activeLine A zero-based line value. + * @param activeCharacter A zero-based character value. + */ + constructor(anchorLine: number, anchorCharacter: number, activeLine: number, activeCharacter: number); + + /** + * A selection is reversed if [active](#Selection.active).isBefore([anchor](#Selection.anchor)). + */ + isReversed: boolean; + } + + /** + * Represents sources that can cause [selection change events](#window.onDidChangeTextEditorSelection). + */ + export enum TextEditorSelectionChangeKind { + /** + * Selection changed due to typing in the editor. + */ + Keyboard = 1, + /** + * Selection change due to clicking in the editor. + */ + Mouse = 2, + /** + * Selection changed because a command ran. + */ + Command = 3 + } + + /** + * Represents an event describing the change in a [text editor's selections](#TextEditor.selections). + */ + export interface TextEditorSelectionChangeEvent { + /** + * The [text editor](#TextEditor) for which the selections have changed. + */ + readonly textEditor: TextEditor; + /** + * The new value for the [text editor's selections](#TextEditor.selections). + */ + readonly selections: ReadonlyArray; + /** + * The [change kind](#TextEditorSelectionChangeKind) which has triggered this + * event. Can be `undefined`. + */ + readonly kind?: TextEditorSelectionChangeKind; + } + + /** + * Represents an event describing the change in a [text editor's visible ranges](#TextEditor.visibleRanges). + */ + export interface TextEditorVisibleRangesChangeEvent { + /** + * The [text editor](#TextEditor) for which the visible ranges have changed. + */ + readonly textEditor: TextEditor; + /** + * The new value for the [text editor's visible ranges](#TextEditor.visibleRanges). + */ + readonly visibleRanges: ReadonlyArray; + } + + /** + * Represents an event describing the change in a [text editor's options](#TextEditor.options). + */ + export interface TextEditorOptionsChangeEvent { + /** + * The [text editor](#TextEditor) for which the options have changed. + */ + readonly textEditor: TextEditor; + /** + * The new value for the [text editor's options](#TextEditor.options). + */ + readonly options: TextEditorOptions; + } + + /** + * Represents an event describing the change of a [text editor's view column](#TextEditor.viewColumn). + */ + export interface TextEditorViewColumnChangeEvent { + /** + * The [text editor](#TextEditor) for which the view column has changed. + */ + readonly textEditor: TextEditor; + /** + * The new value for the [text editor's view column](#TextEditor.viewColumn). + */ + readonly viewColumn: ViewColumn; + } + + /** + * Rendering style of the cursor. + */ + export enum TextEditorCursorStyle { + /** + * Render the cursor as a vertical thick line. + */ + Line = 1, + /** + * Render the cursor as a block filled. + */ + Block = 2, + /** + * Render the cursor as a thick horizontal line. + */ + Underline = 3, + /** + * Render the cursor as a vertical thin line. + */ + LineThin = 4, + /** + * Render the cursor as a block outlined. + */ + BlockOutline = 5, + /** + * Render the cursor as a thin horizontal line. + */ + UnderlineThin = 6 + } + + /** + * Rendering style of the line numbers. + */ + export enum TextEditorLineNumbersStyle { + /** + * Do not render the line numbers. + */ + Off = 0, + /** + * Render the line numbers. + */ + On = 1, + /** + * Render the line numbers with values relative to the primary cursor location. + */ + Relative = 2 + } + + /** + * Represents a [text editor](#TextEditor)'s [options](#TextEditor.options). + */ + export interface TextEditorOptions { + + /** + * The size in spaces a tab takes. This is used for two purposes: + * - the rendering width of a tab character; + * - the number of spaces to insert when [insertSpaces](#TextEditorOptions.insertSpaces) is true. + * + * When getting a text editor's options, this property will always be a number (resolved). + * When setting a text editor's options, this property is optional and it can be a number or `"auto"`. + */ + tabSize?: number | string; + + /** + * When pressing Tab insert [n](#TextEditorOptions.tabSize) spaces. + * When getting a text editor's options, this property will always be a boolean (resolved). + * When setting a text editor's options, this property is optional and it can be a boolean or `"auto"`. + */ + insertSpaces?: boolean | string; + + /** + * The rendering style of the cursor in this editor. + * When getting a text editor's options, this property will always be present. + * When setting a text editor's options, this property is optional. + */ + cursorStyle?: TextEditorCursorStyle; + + /** + * Render relative line numbers w.r.t. the current line number. + * When getting a text editor's options, this property will always be present. + * When setting a text editor's options, this property is optional. + */ + lineNumbers?: TextEditorLineNumbersStyle; + } + + /** + * Represents a handle to a set of decorations + * sharing the same [styling options](#DecorationRenderOptions) in a [text editor](#TextEditor). + * + * To get an instance of a `TextEditorDecorationType` use + * [createTextEditorDecorationType](#window.createTextEditorDecorationType). + */ + export interface TextEditorDecorationType { + + /** + * Internal representation of the handle. + */ + readonly key: string; + + /** + * Remove this decoration type and all decorations on all text editors using it. + */ + dispose(): void; + } + + /** + * Represents different [reveal](#TextEditor.revealRange) strategies in a text editor. + */ + export enum TextEditorRevealType { + /** + * The range will be revealed with as little scrolling as possible. + */ + Default = 0, + /** + * The range will always be revealed in the center of the viewport. + */ + InCenter = 1, + /** + * If the range is outside the viewport, it will be revealed in the center of the viewport. + * Otherwise, it will be revealed with as little scrolling as possible. + */ + InCenterIfOutsideViewport = 2, + /** + * The range will always be revealed at the top of the viewport. + */ + AtTop = 3 + } + + /** + * Represents different positions for rendering a decoration in an [overview ruler](#DecorationRenderOptions.overviewRulerLane). + * The overview ruler supports three lanes. + */ + export enum OverviewRulerLane { + Left = 1, + Center = 2, + Right = 4, + Full = 7 + } + + /** + * Describes the behavior of decorations when typing/editing at their edges. + */ + export enum DecorationRangeBehavior { + /** + * The decoration's range will widen when edits occur at the start or end. + */ + OpenOpen = 0, + /** + * The decoration's range will not widen when edits occur at the start of end. + */ + ClosedClosed = 1, + /** + * The decoration's range will widen when edits occur at the start, but not at the end. + */ + OpenClosed = 2, + /** + * The decoration's range will widen when edits occur at the end, but not at the start. + */ + ClosedOpen = 3 + } + + /** + * Represents options to configure the behavior of showing a [document](#TextDocument) in an [editor](#TextEditor). + */ + export interface TextDocumentShowOptions { + /** + * An optional view column in which the [editor](#TextEditor) should be shown. + * The default is the [active](#ViewColumn.Active), other values are adjusted to + * be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is + * not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) to open the + * editor to the side of the currently active one. + */ + viewColumn?: ViewColumn; + + /** + * An optional flag that when `true` will stop the [editor](#TextEditor) from taking focus. + */ + preserveFocus?: boolean; + + /** + * An optional flag that controls if an [editor](#TextEditor)-tab will be replaced + * with the next editor or if it will be kept. + */ + preview?: boolean; + + /** + * An optional selection to apply for the document in the [editor](#TextEditor). + */ + selection?: Range; + } + + /** + * A reference to one of the workbench colors as defined in https://code.visualstudio.com/docs/getstarted/theme-color-reference. + * Using a theme color is preferred over a custom color as it gives theme authors and users the possibility to change the color. + */ + export class ThemeColor { + + /** + * Creates a reference to a theme color. + * @param id of the color. The available colors are listed in https://code.visualstudio.com/docs/getstarted/theme-color-reference. + */ + constructor(id: string); + } + + /** + * A reference to a named icon. Currently, [File](#ThemeIcon.File), [Folder](#ThemeIcon.Folder), + * and [codicons](https://microsoft.github.io/vscode-codicons/dist/codicon.html) are supported. + * Using a theme icon is preferred over a custom icon as it gives theme authors the possibility to change the icons. + * + * *Note* that theme icons can also be rendered inside labels and descriptions. Places that support theme icons spell this out + * and they use the `$()`-syntax, for instance `quickPick.label = "Hello World $(globe)"`. + */ + export class ThemeIcon { + /** + * Reference to an icon representing a file. The icon is taken from the current file icon theme or a placeholder icon is used. + */ + static readonly File: ThemeIcon; + + /** + * Reference to an icon representing a folder. The icon is taken from the current file icon theme or a placeholder icon is used. + */ + static readonly Folder: ThemeIcon; + + /** + * Creates a reference to a theme icon. + * @param id id of the icon. The available icons are listed in https://microsoft.github.io/vscode-codicons/dist/codicon.html. + */ + constructor(id: string); + } + + /** + * Represents theme specific rendering styles for a [text editor decoration](#TextEditorDecorationType). + */ + export interface ThemableDecorationRenderOptions { + /** + * Background color of the decoration. Use rgba() and define transparent background colors to play well with other decorations. + * Alternatively a color from the color registry can be [referenced](#ThemeColor). + */ + backgroundColor?: string | ThemeColor; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + outline?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'outline' for setting one or more of the individual outline properties. + */ + outlineColor?: string | ThemeColor; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'outline' for setting one or more of the individual outline properties. + */ + outlineStyle?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'outline' for setting one or more of the individual outline properties. + */ + outlineWidth?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + border?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'border' for setting one or more of the individual border properties. + */ + borderColor?: string | ThemeColor; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'border' for setting one or more of the individual border properties. + */ + borderRadius?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'border' for setting one or more of the individual border properties. + */ + borderSpacing?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'border' for setting one or more of the individual border properties. + */ + borderStyle?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + * Better use 'border' for setting one or more of the individual border properties. + */ + borderWidth?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + fontStyle?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + fontWeight?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + textDecoration?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + cursor?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + color?: string | ThemeColor; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + opacity?: string; + + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + letterSpacing?: string; + + /** + * An **absolute path** or an URI to an image to be rendered in the gutter. + */ + gutterIconPath?: string | Uri; + + /** + * Specifies the size of the gutter icon. + * Available values are 'auto', 'contain', 'cover' and any percentage value. + * For further information: https://msdn.microsoft.com/en-us/library/jj127316(v=vs.85).aspx + */ + gutterIconSize?: string; + + /** + * The color of the decoration in the overview ruler. Use rgba() and define transparent colors to play well with other decorations. + */ + overviewRulerColor?: string | ThemeColor; + + /** + * Defines the rendering options of the attachment that is inserted before the decorated text. + */ + before?: ThemableDecorationAttachmentRenderOptions; + + /** + * Defines the rendering options of the attachment that is inserted after the decorated text. + */ + after?: ThemableDecorationAttachmentRenderOptions; + } + + export interface ThemableDecorationAttachmentRenderOptions { + /** + * Defines a text content that is shown in the attachment. Either an icon or a text can be shown, but not both. + */ + contentText?: string; + /** + * An **absolute path** or an URI to an image to be rendered in the attachment. Either an icon + * or a text can be shown, but not both. + */ + contentIconPath?: string | Uri; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + border?: string; + /** + * CSS styling property that will be applied to text enclosed by a decoration. + */ + borderColor?: string | ThemeColor; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + fontStyle?: string; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + fontWeight?: string; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + textDecoration?: string; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + color?: string | ThemeColor; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + backgroundColor?: string | ThemeColor; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + margin?: string; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + width?: string; + /** + * CSS styling property that will be applied to the decoration attachment. + */ + height?: string; + } + + /** + * Represents rendering styles for a [text editor decoration](#TextEditorDecorationType). + */ + export interface DecorationRenderOptions extends ThemableDecorationRenderOptions { + /** + * Should the decoration be rendered also on the whitespace after the line text. + * Defaults to `false`. + */ + isWholeLine?: boolean; + + /** + * Customize the growing behavior of the decoration when edits occur at the edges of the decoration's range. + * Defaults to `DecorationRangeBehavior.OpenOpen`. + */ + rangeBehavior?: DecorationRangeBehavior; + + /** + * The position in the overview ruler where the decoration should be rendered. + */ + overviewRulerLane?: OverviewRulerLane; + + /** + * Overwrite options for light themes. + */ + light?: ThemableDecorationRenderOptions; + + /** + * Overwrite options for dark themes. + */ + dark?: ThemableDecorationRenderOptions; + } + + /** + * Represents options for a specific decoration in a [decoration set](#TextEditorDecorationType). + */ + export interface DecorationOptions { + + /** + * Range to which this decoration is applied. The range must not be empty. + */ + range: Range; + + /** + * A message that should be rendered when hovering over the decoration. + */ + hoverMessage?: MarkedString | MarkedString[]; + + /** + * Render options applied to the current decoration. For performance reasons, keep the + * number of decoration specific options small, and use decoration types wherever possible. + */ + renderOptions?: DecorationInstanceRenderOptions; + } + + export interface ThemableDecorationInstanceRenderOptions { + /** + * Defines the rendering options of the attachment that is inserted before the decorated text. + */ + before?: ThemableDecorationAttachmentRenderOptions; + + /** + * Defines the rendering options of the attachment that is inserted after the decorated text. + */ + after?: ThemableDecorationAttachmentRenderOptions; + } + + export interface DecorationInstanceRenderOptions extends ThemableDecorationInstanceRenderOptions { + /** + * Overwrite options for light themes. + */ + light?: ThemableDecorationInstanceRenderOptions; + + /** + * Overwrite options for dark themes. + */ + dark?: ThemableDecorationInstanceRenderOptions; + } + + /** + * Represents an editor that is attached to a [document](#TextDocument). + */ + export interface TextEditor { + + /** + * The document associated with this text editor. The document will be the same for the entire lifetime of this text editor. + */ + readonly document: TextDocument; + + /** + * The primary selection on this text editor. Shorthand for `TextEditor.selections[0]`. + */ + selection: Selection; + + /** + * The selections in this text editor. The primary selection is always at index 0. + */ + selections: Selection[]; + + /** + * The current visible ranges in the editor (vertically). + * This accounts only for vertical scrolling, and not for horizontal scrolling. + */ + readonly visibleRanges: Range[]; + + /** + * Text editor options. + */ + options: TextEditorOptions; + + /** + * The column in which this editor shows. Will be `undefined` in case this + * isn't one of the main editors, e.g. an embedded editor, or when the editor + * column is larger than three. + */ + viewColumn?: ViewColumn; + + /** + * Perform an edit on the document associated with this text editor. + * + * The given callback-function is invoked with an [edit-builder](#TextEditorEdit) which must + * be used to make edits. Note that the edit-builder is only valid while the + * callback executes. + * + * @param callback A function which can create edits using an [edit-builder](#TextEditorEdit). + * @param options The undo/redo behavior around this edit. By default, undo stops will be created before and after this edit. + * @return A promise that resolves with a value indicating if the edits could be applied. + */ + edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable; + + /** + * Insert a [snippet](#SnippetString) and put the editor into snippet mode. "Snippet mode" + * means the editor adds placeholders and additional cursors so that the user can complete + * or accept the snippet. + * + * @param snippet The snippet to insert in this edit. + * @param location Position or range at which to insert the snippet, defaults to the current editor selection or selections. + * @param options The undo/redo behavior around this edit. By default, undo stops will be created before and after this edit. + * @return A promise that resolves with a value indicating if the snippet could be inserted. Note that the promise does not signal + * that the snippet is completely filled-in or accepted. + */ + insertSnippet(snippet: SnippetString, location?: Position | Range | ReadonlyArray | ReadonlyArray, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable; + + /** + * Adds a set of decorations to the text editor. If a set of decorations already exists with + * the given [decoration type](#TextEditorDecorationType), they will be replaced. + * + * @see [createTextEditorDecorationType](#window.createTextEditorDecorationType). + * + * @param decorationType A decoration type. + * @param rangesOrOptions Either [ranges](#Range) or more detailed [options](#DecorationOptions). + */ + setDecorations(decorationType: TextEditorDecorationType, rangesOrOptions: Range[] | DecorationOptions[]): void; + + /** + * Scroll as indicated by `revealType` in order to reveal the given range. + * + * @param range A range. + * @param revealType The scrolling strategy for revealing `range`. + */ + revealRange(range: Range, revealType?: TextEditorRevealType): void; + + /** + * ~~Show the text editor.~~ + * + * @deprecated Use [window.showTextDocument](#window.showTextDocument) instead. + * + * @param column The [column](#ViewColumn) in which to show this editor. + * This method shows unexpected behavior and will be removed in the next major update. + */ + show(column?: ViewColumn): void; + + /** + * ~~Hide the text editor.~~ + * + * @deprecated Use the command `workbench.action.closeActiveEditor` instead. + * This method shows unexpected behavior and will be removed in the next major update. + */ + hide(): void; + } + + /** + * Represents an end of line character sequence in a [document](#TextDocument). + */ + export enum EndOfLine { + /** + * The line feed `\n` character. + */ + LF = 1, + /** + * The carriage return line feed `\r\n` sequence. + */ + CRLF = 2 + } + + /** + * A complex edit that will be applied in one transaction on a TextEditor. + * This holds a description of the edits and if the edits are valid (i.e. no overlapping regions, document was not changed in the meantime, etc.) + * they can be applied on a [document](#TextDocument) associated with a [text editor](#TextEditor). + */ + export interface TextEditorEdit { + /** + * Replace a certain text region with a new value. + * You can use \r\n or \n in `value` and they will be normalized to the current [document](#TextDocument). + * + * @param location The range this operation should remove. + * @param value The new text this operation should insert after removing `location`. + */ + replace(location: Position | Range | Selection, value: string): void; + + /** + * Insert text at a location. + * You can use \r\n or \n in `value` and they will be normalized to the current [document](#TextDocument). + * Although the equivalent text edit can be made with [replace](#TextEditorEdit.replace), `insert` will produce a different resulting selection (it will get moved). + * + * @param location The position where the new text should be inserted. + * @param value The new text this operation should insert. + */ + insert(location: Position, value: string): void; + + /** + * Delete a certain text region. + * + * @param location The range this operation should remove. + */ + delete(location: Range | Selection): void; + + /** + * Set the end of line sequence. + * + * @param endOfLine The new end of line for the [document](#TextDocument). + */ + setEndOfLine(endOfLine: EndOfLine): void; + } + + /** + * A universal resource identifier representing either a file on disk + * or another resource, like untitled resources. + */ + export class Uri { + + /** + * Create an URI from a string, e.g. `http://www.msft.com/some/path`, + * `file:///usr/home`, or `scheme:with/path`. + * + * *Note* that for a while uris without a `scheme` were accepted. That is not correct + * as all uris should have a scheme. To avoid breakage of existing code the optional + * `strict`-argument has been added. We *strongly* advise to use it, e.g. `Uri.parse('my:uri', true)` + * + * @see [Uri.toString](#Uri.toString) + * @param value The string value of an Uri. + * @param strict Throw an error when `value` is empty or when no `scheme` can be parsed. + * @return A new Uri instance. + */ + static parse(value: string, strict?: boolean): Uri; + + /** + * Create an URI from a file system path. The [scheme](#Uri.scheme) + * will be `file`. + * + * The *difference* between `Uri#parse` and `Uri#file` is that the latter treats the argument + * as path, not as stringified-uri. E.g. `Uri.file(path)` is *not* the same as + * `Uri.parse('file://' + path)` because the path might contain characters that are + * interpreted (# and ?). See the following sample: + * ```ts + const good = URI.file('/coding/c#/project1'); + good.scheme === 'file'; + good.path === '/coding/c#/project1'; + good.fragment === ''; + + const bad = URI.parse('file://' + '/coding/c#/project1'); + bad.scheme === 'file'; + bad.path === '/coding/c'; // path is now broken + bad.fragment === '/project1'; + ``` + * + * @param path A file system or UNC path. + * @return A new Uri instance. + */ + static file(path: string): Uri; + + /** + * Create a new uri which path is the result of joining + * the path of the base uri with the provided path segments. + * + * - Note 1: `joinPath` only affects the path component + * and all other components (scheme, authority, query, and fragment) are + * left as they are. + * - Note 2: The base uri must have a path; an error is thrown otherwise. + * + * The path segments are normalized in the following ways: + * - sequences of path separators (`/` or `\`) are replaced with a single separator + * - for `file`-uris on windows, the backslash-character (`\`) is considered a path-separator + * - the `..`-segment denotes the parent segment, the `.` denotes the current segment + * - paths have a root which always remains, for instance on windows drive-letters are roots + * so that is true: `joinPath(Uri.file('file:///c:/root'), '../../other').fsPath === 'c:/other'` + * + * @param base An uri. Must have a path. + * @param pathSegments One more more path fragments + * @returns A new uri which path is joined with the given fragments + */ + static joinPath(base: Uri, ...pathSegments: string[]): Uri; + + /** + * Use the `file` and `parse` factory functions to create new `Uri` objects. + */ + private constructor(scheme: string, authority: string, path: string, query: string, fragment: string); + + /** + * Scheme is the `http` part of `http://www.msft.com/some/path?query#fragment`. + * The part before the first colon. + */ + readonly scheme: string; + + /** + * Authority is the `www.msft.com` part of `http://www.msft.com/some/path?query#fragment`. + * The part between the first double slashes and the next slash. + */ + readonly authority: string; + + /** + * Path is the `/some/path` part of `http://www.msft.com/some/path?query#fragment`. + */ + readonly path: string; + + /** + * Query is the `query` part of `http://www.msft.com/some/path?query#fragment`. + */ + readonly query: string; + + /** + * Fragment is the `fragment` part of `http://www.msft.com/some/path?query#fragment`. + */ + readonly fragment: string; + + /** + * The string representing the corresponding file system path of this Uri. + * + * Will handle UNC paths and normalize windows drive letters to lower-case. Also + * uses the platform specific path separator. + * + * * Will *not* validate the path for invalid characters and semantics. + * * Will *not* look at the scheme of this Uri. + * * The resulting string shall *not* be used for display purposes but + * for disk operations, like `readFile` et al. + * + * The *difference* to the [`path`](#Uri.path)-property is the use of the platform specific + * path separator and the handling of UNC paths. The sample below outlines the difference: + * ```ts + const u = URI.parse('file://server/c$/folder/file.txt') + u.authority === 'server' + u.path === '/shares/c$/file.txt' + u.fsPath === '\\server\c$\folder\file.txt' + ``` + */ + readonly fsPath: string; + + /** + * Derive a new Uri from this Uri. + * + * ```ts + * let file = Uri.parse('before:some/file/path'); + * let other = file.with({ scheme: 'after' }); + * assert.ok(other.toString() === 'after:some/file/path'); + * ``` + * + * @param change An object that describes a change to this Uri. To unset components use `null` or + * the empty string. + * @return A new Uri that reflects the given change. Will return `this` Uri if the change + * is not changing anything. + */ + with(change: { scheme?: string; authority?: string; path?: string; query?: string; fragment?: string }): Uri; + + /** + * Returns a string representation of this Uri. The representation and normalization + * of a URI depends on the scheme. + * + * * The resulting string can be safely used with [Uri.parse](#Uri.parse). + * * The resulting string shall *not* be used for display purposes. + * + * *Note* that the implementation will encode _aggressive_ which often leads to unexpected, + * but not incorrect, results. For instance, colons are encoded to `%3A` which might be unexpected + * in file-uri. Also `&` and `=` will be encoded which might be unexpected for http-uris. For stability + * reasons this cannot be changed anymore. If you suffer from too aggressive encoding you should use + * the `skipEncoding`-argument: `uri.toString(true)`. + * + * @param skipEncoding Do not percentage-encode the result, defaults to `false`. Note that + * the `#` and `?` characters occurring in the path will always be encoded. + * @returns A string representation of this Uri. + */ + toString(skipEncoding?: boolean): string; + + /** + * Returns a JSON representation of this Uri. + * + * @return An object. + */ + toJSON(): any; + } + + /** + * A cancellation token is passed to an asynchronous or long running + * operation to request cancellation, like cancelling a request + * for completion items because the user continued to type. + * + * To get an instance of a `CancellationToken` use a + * [CancellationTokenSource](#CancellationTokenSource). + */ + export interface CancellationToken { + + /** + * Is `true` when the token has been cancelled, `false` otherwise. + */ + isCancellationRequested: boolean; + + /** + * An [event](#Event) which fires upon cancellation. + */ + onCancellationRequested: Event; + } + + /** + * A cancellation source creates and controls a [cancellation token](#CancellationToken). + */ + export class CancellationTokenSource { + + /** + * The cancellation token of this source. + */ + token: CancellationToken; + + /** + * Signal cancellation on the token. + */ + cancel(): void; + + /** + * Dispose object and free resources. + */ + dispose(): void; + } + + /** + * Represents a type which can release resources, such + * as event listening or a timer. + */ + export class Disposable { + + /** + * Combine many disposable-likes into one. Use this method + * when having objects with a dispose function which are not + * instances of Disposable. + * + * @param disposableLikes Objects that have at least a `dispose`-function member. + * @return Returns a new disposable which, upon dispose, will + * dispose all provided disposables. + */ + static from(...disposableLikes: { dispose: () => any }[]): Disposable; + + /** + * Creates a new Disposable calling the provided function + * on dispose. + * @param callOnDispose Function that disposes something. + */ + constructor(callOnDispose: Function); + + /** + * Dispose this object. + */ + dispose(): any; + } + + /** + * Represents a typed event. + * + * A function that represents an event to which you subscribe by calling it with + * a listener function as argument. + * + * @sample `item.onDidChange(function(event) { console.log("Event happened: " + event); });` + */ + export interface Event { + + /** + * A function that represents an event to which you subscribe by calling it with + * a listener function as argument. + * + * @param listener The listener function will be called when the event happens. + * @param thisArgs The `this`-argument which will be used when calling the event listener. + * @param disposables An array to which a [disposable](#Disposable) will be added. + * @return A disposable which unsubscribes the event listener. + */ + (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]): Disposable; + } + + /** + * An event emitter can be used to create and manage an [event](#Event) for others + * to subscribe to. One emitter always owns one event. + * + * Use this class if you want to provide event from within your extension, for instance + * inside a [TextDocumentContentProvider](#TextDocumentContentProvider) or when providing + * API to other extensions. + */ + export class EventEmitter { + + /** + * The event listeners can subscribe to. + */ + event: Event; + + /** + * Notify all subscribers of the [event](#EventEmitter.event). Failure + * of one or more listener will not fail this function call. + * + * @param data The event object. + */ + fire(data: T): void; + + /** + * Dispose this object and free resources. + */ + dispose(): void; + } + + /** + * A file system watcher notifies about changes to files and folders + * on disk or from other [FileSystemProviders](#FileSystemProvider). + * + * To get an instance of a `FileSystemWatcher` use + * [createFileSystemWatcher](#workspace.createFileSystemWatcher). + */ + export interface FileSystemWatcher extends Disposable { + + /** + * true if this file system watcher has been created such that + * it ignores creation file system events. + */ + ignoreCreateEvents: boolean; + + /** + * true if this file system watcher has been created such that + * it ignores change file system events. + */ + ignoreChangeEvents: boolean; + + /** + * true if this file system watcher has been created such that + * it ignores delete file system events. + */ + ignoreDeleteEvents: boolean; + + /** + * An event which fires on file/folder creation. + */ + onDidCreate: Event; + + /** + * An event which fires on file/folder change. + */ + onDidChange: Event; + + /** + * An event which fires on file/folder deletion. + */ + onDidDelete: Event; + } + + /** + * A text document content provider allows to add readonly documents + * to the editor, such as source from a dll or generated html from md. + * + * Content providers are [registered](#workspace.registerTextDocumentContentProvider) + * for a [uri-scheme](#Uri.scheme). When a uri with that scheme is to + * be [loaded](#workspace.openTextDocument) the content provider is + * asked. + */ + export interface TextDocumentContentProvider { + + /** + * An event to signal a resource has changed. + */ + onDidChange?: Event; + + /** + * Provide textual content for a given uri. + * + * The editor will use the returned string-content to create a readonly + * [document](#TextDocument). Resources allocated should be released when + * the corresponding document has been [closed](#workspace.onDidCloseTextDocument). + * + * **Note**: The contents of the created [document](#TextDocument) might not be + * identical to the provided text due to end-of-line-sequence normalization. + * + * @param uri An uri which scheme matches the scheme this provider was [registered](#workspace.registerTextDocumentContentProvider) for. + * @param token A cancellation token. + * @return A string or a thenable that resolves to such. + */ + provideTextDocumentContent(uri: Uri, token: CancellationToken): ProviderResult; + } + + /** + * Represents an item that can be selected from + * a list of items. + */ + export interface QuickPickItem { + + /** + * A human-readable string which is rendered prominent. Supports rendering of [theme icons](#ThemeIcon) via + * the `$()`-syntax. + */ + label: string; + + /** + * A human-readable string which is rendered less prominent in the same line. Supports rendering of + * [theme icons](#ThemeIcon) via the `$()`-syntax. + */ + description?: string; + + /** + * A human-readable string which is rendered less prominent in a separate line. Supports rendering of + * [theme icons](#ThemeIcon) via the `$()`-syntax. + */ + detail?: string; + + /** + * Optional flag indicating if this item is picked initially. + * (Only honored when the picker allows multiple selections.) + * + * @see [QuickPickOptions.canPickMany](#QuickPickOptions.canPickMany) + */ + picked?: boolean; + + /** + * Always show this item. + */ + alwaysShow?: boolean; + } + + /** + * Options to configure the behavior of the quick pick UI. + */ + export interface QuickPickOptions { + /** + * An optional flag to include the description when filtering the picks. + */ + matchOnDescription?: boolean; + + /** + * An optional flag to include the detail when filtering the picks. + */ + matchOnDetail?: boolean; + + /** + * An optional string to show as placeholder in the input box to guide the user what to pick on. + */ + placeHolder?: string; + + /** + * Set to `true` to keep the picker open when focus moves to another part of the editor or to another window. + */ + ignoreFocusOut?: boolean; + + /** + * An optional flag to make the picker accept multiple selections, if true the result is an array of picks. + */ + canPickMany?: boolean; + + /** + * An optional function that is invoked whenever an item is selected. + */ + onDidSelectItem?(item: QuickPickItem | string): any; + } + + /** + * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. + */ + export interface WorkspaceFolderPickOptions { + + /** + * An optional string to show as placeholder in the input box to guide the user what to pick on. + */ + placeHolder?: string; + + /** + * Set to `true` to keep the picker open when focus moves to another part of the editor or to another window. + */ + ignoreFocusOut?: boolean; + } + + /** + * Options to configure the behaviour of a file open dialog. + * + * * Note 1: A dialog can select files, folders, or both. This is not true for Windows + * which enforces to open either files or folder, but *not both*. + * * Note 2: Explicitly setting `canSelectFiles` and `canSelectFolders` to `false` is futile + * and the editor then silently adjusts the options to select files. + */ + export interface OpenDialogOptions { + /** + * The resource the dialog shows when opened. + */ + defaultUri?: Uri; + + /** + * A human-readable string for the open button. + */ + openLabel?: string; + + /** + * Allow to select files, defaults to `true`. + */ + canSelectFiles?: boolean; + + /** + * Allow to select folders, defaults to `false`. + */ + canSelectFolders?: boolean; + + /** + * Allow to select many files or folders. + */ + canSelectMany?: boolean; + + /** + * A set of file filters that are used by the dialog. Each entry is a human-readable label, + * like "TypeScript", and an array of extensions, e.g. + * ```ts + * { + * 'Images': ['png', 'jpg'] + * 'TypeScript': ['ts', 'tsx'] + * } + * ``` + */ + filters?: { [name: string]: string[] }; + + /** + * Dialog title. + * + * This parameter might be ignored, as not all operating systems display a title on open dialogs + * (for example, macOS). + */ + title?: string; + } + + /** + * Options to configure the behaviour of a file save dialog. + */ + export interface SaveDialogOptions { + /** + * The resource the dialog shows when opened. + */ + defaultUri?: Uri; + + /** + * A human-readable string for the save button. + */ + saveLabel?: string; + + /** + * A set of file filters that are used by the dialog. Each entry is a human-readable label, + * like "TypeScript", and an array of extensions, e.g. + * ```ts + * { + * 'Images': ['png', 'jpg'] + * 'TypeScript': ['ts', 'tsx'] + * } + * ``` + */ + filters?: { [name: string]: string[] }; + + /** + * Dialog title. + * + * This parameter might be ignored, as not all operating systems display a title on save dialogs + * (for example, macOS). + */ + title?: string; + } + + /** + * Represents an action that is shown with an information, warning, or + * error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * @see [showWarningMessage](#window.showWarningMessage) + * @see [showErrorMessage](#window.showErrorMessage) + */ + export interface MessageItem { + + /** + * A short title like 'Retry', 'Open Log' etc. + */ + title: string; + + /** + * A hint for modal dialogs that the item should be triggered + * when the user cancels the dialog (e.g. by pressing the ESC + * key). + * + * Note: this option is ignored for non-modal messages. + */ + isCloseAffordance?: boolean; + } + + /** + * Options to configure the behavior of the message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * @see [showWarningMessage](#window.showWarningMessage) + * @see [showErrorMessage](#window.showErrorMessage) + */ + export interface MessageOptions { + + /** + * Indicates that this message should be modal. + */ + modal?: boolean; + } + + /** + * Options to configure the behavior of the input box UI. + */ + export interface InputBoxOptions { + + /** + * The value to prefill in the input box. + */ + value?: string; + + /** + * Selection of the prefilled [`value`](#InputBoxOptions.value). Defined as tuple of two number where the + * first is the inclusive start index and the second the exclusive end index. When `undefined` the whole + * word will be selected, when empty (start equals end) only the cursor will be set, + * otherwise the defined range will be selected. + */ + valueSelection?: [number, number]; + + /** + * The text to display underneath the input box. + */ + prompt?: string; + + /** + * An optional string to show as placeholder in the input box to guide the user what to type. + */ + placeHolder?: string; + + /** + * Controls if a password input is shown. Password input hides the typed text. + */ + password?: boolean; + + /** + * Set to `true` to keep the input box open when focus moves to another part of the editor or to another window. + */ + ignoreFocusOut?: boolean; + + /** + * An optional function that will be called to validate input and to give a hint + * to the user. + * + * @param value The current value of the input box. + * @return A human-readable string which is presented as diagnostic message. + * Return `undefined`, `null`, or the empty string when 'value' is valid. + */ + validateInput?(value: string): string | undefined | null | Thenable; + } + + /** + * A relative pattern is a helper to construct glob patterns that are matched + * relatively to a base path. The base path can either be an absolute file path + * or a [workspace folder](#WorkspaceFolder). + */ + export class RelativePattern { + + /** + * A base file path to which this pattern will be matched against relatively. + */ + base: string; + + /** + * A file glob pattern like `*.{ts,js}` that will be matched on file paths + * relative to the base path. + * + * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`, + * the file glob pattern will match on `index.js`. + */ + pattern: string; + + /** + * Creates a new relative pattern object with a base path and pattern to match. This pattern + * will be matched on file paths relative to the base path. + * + * @param base A base file path to which this pattern will be matched against relatively. + * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on file paths + * relative to the base path. + */ + constructor(base: WorkspaceFolder | string, pattern: string) + } + + /** + * A file glob pattern to match file paths against. This can either be a glob pattern string + * (like `**​/*.{ts,js}` or `*.{ts,js}`) or a [relative pattern](#RelativePattern). + * + * Glob patterns can have the following syntax: + * * `*` to match one or more characters in a path segment + * * `?` to match on one character in a path segment + * * `**` to match any number of path segments, including none + * * `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) + * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + * + * Note: a backslash (`\`) is not valid within a glob pattern. If you have an existing file + * path to match against, consider to use the [relative pattern](#RelativePattern) support + * that takes care of converting any backslash into slash. Otherwise, make sure to convert + * any backslash to slash when creating the glob pattern. + */ + export type GlobPattern = string | RelativePattern; + + /** + * A document filter denotes a document by different properties like + * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of + * its resource, or a glob-pattern that is applied to the [path](#TextDocument.fileName). + * + * @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` + * @sample A language filter that applies to all package.json paths: `{ language: 'json', scheme: 'untitled', pattern: '**​/package.json' }` + */ + export interface DocumentFilter { + + /** + * A language id, like `typescript`. + */ + language?: string; + + /** + * A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + */ + scheme?: string; + + /** + * A [glob pattern](#GlobPattern) that is matched on the absolute path of the document. Use a [relative pattern](#RelativePattern) + * to filter documents to a [workspace folder](#WorkspaceFolder). + */ + pattern?: GlobPattern; + } + + /** + * A language selector is the combination of one or many language identifiers + * and [language filters](#DocumentFilter). + * + * *Note* that a document selector that is just a language identifier selects *all* + * documents, even those that are not saved on disk. Only use such selectors when + * a feature works without further context, e.g. without the need to resolve related + * 'files'. + * + * @sample `let sel:DocumentSelector = { scheme: 'file', language: 'typescript' }`; + */ + export type DocumentSelector = DocumentFilter | string | Array; + + /** + * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), + * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves + * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a + * thenable. + * + * The snippets below are all valid implementations of the [`HoverProvider`](#HoverProvider): + * + * ```ts + * let a: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return new Hover('Hello World'); + * } + * } + * + * let b: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return new Promise(resolve => { + * resolve(new Hover('Hello World')); + * }); + * } + * } + * + * let c: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return; // undefined + * } + * } + * ``` + */ + export type ProviderResult = T | undefined | null | Thenable; + + /** + * Kind of a code action. + * + * Kinds are a hierarchical list of identifiers separated by `.`, e.g. `"refactor.extract.function"`. + * + * Code action kinds are used by VS Code for UI elements such as the refactoring context menu. Users + * can also trigger code actions with a specific kind with the `editor.action.codeAction` command. + */ + export class CodeActionKind { + /** + * Empty kind. + */ + static readonly Empty: CodeActionKind; + + /** + * Base kind for quickfix actions: `quickfix`. + * + * Quick fix actions address a problem in the code and are shown in the normal code action context menu. + */ + static readonly QuickFix: CodeActionKind; + + /** + * Base kind for refactoring actions: `refactor` + * + * Refactoring actions are shown in the refactoring context menu. + */ + static readonly Refactor: CodeActionKind; + + /** + * Base kind for refactoring extraction actions: `refactor.extract` + * + * Example extract actions: + * + * - Extract method + * - Extract function + * - Extract variable + * - Extract interface from class + * - ... + */ + static readonly RefactorExtract: CodeActionKind; + + /** + * Base kind for refactoring inline actions: `refactor.inline` + * + * Example inline actions: + * + * - Inline function + * - Inline variable + * - Inline constant + * - ... + */ + static readonly RefactorInline: CodeActionKind; + + /** + * Base kind for refactoring rewrite actions: `refactor.rewrite` + * + * Example rewrite actions: + * + * - Convert JavaScript function to class + * - Add or remove parameter + * - Encapsulate field + * - Make method static + * - Move method to base class + * - ... + */ + static readonly RefactorRewrite: CodeActionKind; + + /** + * Base kind for source actions: `source` + * + * Source code actions apply to the entire file. They must be explicitly requested and will not show in the + * normal [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) menu. Source actions + * can be run on save using `editor.codeActionsOnSave` and are also shown in the `source` context menu. + */ + static readonly Source: CodeActionKind; + + /** + * Base kind for an organize imports source action: `source.organizeImports`. + */ + static readonly SourceOrganizeImports: CodeActionKind; + + /** + * Base kind for auto-fix source actions: `source.fixAll`. + * + * Fix all actions automatically fix errors that have a clear fix that do not require user input. + * They should not suppress errors or perform unsafe fixes such as generating new types or classes. + */ + static readonly SourceFixAll: CodeActionKind; + + private constructor(value: string); + + /** + * String value of the kind, e.g. `"refactor.extract.function"`. + */ + readonly value: string; + + /** + * Create a new kind by appending a more specific selector to the current kind. + * + * Does not modify the current kind. + */ + append(parts: string): CodeActionKind; + + /** + * Checks if this code action kind intersects `other`. + * + * The kind `"refactor.extract"` for example intersects `refactor`, `"refactor.extract"` and ``"refactor.extract.function"`, + * but not `"unicorn.refactor.extract"`, or `"refactor.extractAll"`. + * + * @param other Kind to check. + */ + intersects(other: CodeActionKind): boolean; + + /** + * Checks if `other` is a sub-kind of this `CodeActionKind`. + * + * The kind `"refactor.extract"` for example contains `"refactor.extract"` and ``"refactor.extract.function"`, + * but not `"unicorn.refactor.extract"`, or `"refactor.extractAll"` or `refactor`. + * + * @param other Kind to check. + */ + contains(other: CodeActionKind): boolean; + } + + /** + * Contains additional diagnostic information about the context in which + * a [code action](#CodeActionProvider.provideCodeActions) is run. + */ + export interface CodeActionContext { + /** + * An array of diagnostics. + */ + readonly diagnostics: ReadonlyArray; + + /** + * Requested kind of actions to return. + * + * Actions not of this kind are filtered out before being shown by the [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action). + */ + readonly only?: CodeActionKind; + } + + /** + * A code action represents a change that can be performed in code, e.g. to fix a problem or + * to refactor code. + * + * A CodeAction must set either [`edit`](#CodeAction.edit) and/or a [`command`](#CodeAction.command). If both are supplied, the `edit` is applied first, then the command is executed. + */ + export class CodeAction { + + /** + * A short, human-readable, title for this code action. + */ + title: string; + + /** + * A [workspace edit](#WorkspaceEdit) this code action performs. + */ + edit?: WorkspaceEdit; + + /** + * [Diagnostics](#Diagnostic) that this code action resolves. + */ + diagnostics?: Diagnostic[]; + + /** + * A [command](#Command) this code action executes. + * + * If this command throws an exception, VS Code displays the exception message to users in the editor at the + * current cursor position. + */ + command?: Command; + + /** + * [Kind](#CodeActionKind) of the code action. + * + * Used to filter code actions. + */ + kind?: CodeActionKind; + + /** + * Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + * by keybindings. + * + * A quick fix should be marked preferred if it properly addresses the underlying error. + * A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + */ + isPreferred?: boolean; + + /** + * Marks that the code action cannot currently be applied. + * + * - Disabled code actions are not shown in automatic [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) + * code action menu. + * + * - Disabled actions are shown as faded out in the code action menu when the user request a more specific type + * of code action, such as refactorings. + * + * - If the user has a [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) + * that auto applies a code action and only a disabled code actions are returned, VS Code will show the user an + * error message with `reason` in the editor. + */ + disabled?: { + /** + * Human readable description of why the code action is currently disabled. + * + * This is displayed in the code actions UI. + */ + readonly reason: string; + }; + + /** + * Creates a new code action. + * + * A code action must have at least a [title](#CodeAction.title) and [edits](#CodeAction.edit) + * and/or a [command](#CodeAction.command). + * + * @param title The title of the code action. + * @param kind The kind of the code action. + */ + constructor(title: string, kind?: CodeActionKind); + } + + /** + * The code action interface defines the contract between extensions and + * the [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + * + * A code action can be any command that is [known](#commands.getCommands) to the system. + */ + export interface CodeActionProvider { + /** + * Provide commands for the given document and range. + * + * @param document The document in which the command was invoked. + * @param range The selector or range for which the command was invoked. This will always be a selection if + * there is a currently active editor. + * @param context Context carrying additional information. + * @param token A cancellation token. + * @return An array of commands, quick fixes, or refactorings or a thenable of such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideCodeActions(document: TextDocument, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult<(Command | CodeAction)[]>; + } + + /** + * Metadata about the type of code actions that a [CodeActionProvider](#CodeActionProvider) provides. + */ + export interface CodeActionProviderMetadata { + /** + * List of [CodeActionKinds](#CodeActionKind) that a [CodeActionProvider](#CodeActionProvider) may return. + * + * This list is used to determine if a given `CodeActionProvider` should be invoked or not. + * To avoid unnecessary computation, every `CodeActionProvider` should list use `providedCodeActionKinds`. The + * list of kinds may either be generic, such as `[CodeActionKind.Refactor]`, or list out every kind provided, + * such as `[CodeActionKind.Refactor.Extract.append('function'), CodeActionKind.Refactor.Extract.append('constant'), ...]`. + */ + readonly providedCodeActionKinds?: ReadonlyArray; + + /** + * Static documentation for a class of code actions. + * + * Documentation from the provider is shown in the code actions menu if either: + * + * - Code actions of `kind` are requested by VS Code. In this case, VS Code will show the documentation that + * most closely matches the requested code action kind. For example, if a provider has documentation for + * both `Refactor` and `RefactorExtract`, when the user requests code actions for `RefactorExtract`, + * VS Code will use the documentation for `RefactorExtract` instead of the documentation for `Refactor`. + * + * - Any code actions of `kind` are returned by the provider. + * + * At most one documentation entry will be shown per provider. + */ + readonly documentation?: ReadonlyArray<{ + /** + * The kind of the code action being documented. + * + * If the kind is generic, such as `CodeActionKind.Refactor`, the documentation will be shown whenever any + * refactorings are returned. If the kind if more specific, such as `CodeActionKind.RefactorExtract`, the + * documentation will only be shown when extract refactoring code actions are returned. + */ + readonly kind: CodeActionKind; + + /** + * Command that displays the documentation to the user. + * + * This can display the documentation directly in VS Code or open a website using [`env.openExternal`](#env.openExternal); + * + * The title of this documentation code action is taken from [`Command.title`](#Command.title) + */ + readonly command: Command; + }>; + } + + /** + * A code lens represents a [command](#Command) that should be shown along with + * source text, like the number of references, a way to run tests, etc. + * + * A code lens is _unresolved_ when no command is associated to it. For performance + * reasons the creation of a code lens and resolving should be done to two stages. + * + * @see [CodeLensProvider.provideCodeLenses](#CodeLensProvider.provideCodeLenses) + * @see [CodeLensProvider.resolveCodeLens](#CodeLensProvider.resolveCodeLens) + */ + export class CodeLens { + + /** + * The range in which this code lens is valid. Should only span a single line. + */ + range: Range; + + /** + * The command this code lens represents. + */ + command?: Command; + + /** + * `true` when there is a command associated. + */ + readonly isResolved: boolean; + + /** + * Creates a new code lens object. + * + * @param range The range to which this code lens applies. + * @param command The command associated to this code lens. + */ + constructor(range: Range, command?: Command); + } + + /** + * A code lens provider adds [commands](#Command) to source text. The commands will be shown + * as dedicated horizontal lines in between the source text. + */ + export interface CodeLensProvider { + + /** + * An optional event to signal that the code lenses from this provider have changed. + */ + onDidChangeCodeLenses?: Event; + + /** + * Compute a list of [lenses](#CodeLens). This call should return as fast as possible and if + * computing the commands is expensive implementors should only return code lens objects with the + * range set and implement [resolve](#CodeLensProvider.resolveCodeLens). + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of code lenses or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideCodeLenses(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * This function will be called for each visible code lens, usually when scrolling and after + * calls to [compute](#CodeLensProvider.provideCodeLenses)-lenses. + * + * @param codeLens Code lens that must be resolved. + * @param token A cancellation token. + * @return The given, resolved code lens or thenable that resolves to such. + */ + resolveCodeLens?(codeLens: T, token: CancellationToken): ProviderResult; + } + + /** + * Information about where a symbol is defined. + * + * Provides additional metadata over normal [location](#Location) definitions, including the range of + * the defining symbol + */ + export type DefinitionLink = LocationLink; + + /** + * The definition of a symbol represented as one or many [locations](#Location). + * For most programming languages there is only one location at which a symbol is + * defined. + */ + export type Definition = Location | Location[]; + + /** + * The definition provider interface defines the contract between extensions and + * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) + * and peek definition features. + */ + export interface DefinitionProvider { + + /** + * Provide the definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * The implementation provider interface defines the contract between extensions and + * the go to implementation feature. + */ + export interface ImplementationProvider { + + /** + * Provide the implementations of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideImplementation(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * The type definition provider defines the contract between extensions and + * the go to type definition feature. + */ + export interface TypeDefinitionProvider { + + /** + * Provide the type definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * The declaration of a symbol representation as one or many [locations](#Location) + * or [location links](#LocationLink). + */ + export type Declaration = Location | Location[] | LocationLink[]; + + /** + * The declaration provider interface defines the contract between extensions and + * the go to declaration feature. + */ + export interface DeclarationProvider { + + /** + * Provide the declaration of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A declaration or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideDeclaration(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * The MarkdownString represents human-readable text that supports formatting via the + * markdown syntax. Standard markdown is supported, also tables, but no embedded html. + * + * When created with `supportThemeIcons` then rendering of [theme icons](#ThemeIcon) via + * the `$()`-syntax is supported. + */ + export class MarkdownString { + + /** + * The markdown string. + */ + value: string; + + /** + * Indicates that this markdown string is from a trusted source. Only *trusted* + * markdown supports links that execute commands, e.g. `[Run it](command:myCommandId)`. + */ + isTrusted?: boolean; + + /** + * Indicates that this markdown string can contain [ThemeIcons](#ThemeIcon), e.g. `$(zap)`. + */ + readonly supportThemeIcons?: boolean; + + /** + * Creates a new markdown string with the given value. + * + * @param value Optional, initial value. + * @param supportThemeIcons Optional, Specifies whether [ThemeIcons](#ThemeIcon) are supported within the [`MarkdownString`](#MarkdownString). + */ + constructor(value?: string, supportThemeIcons?: boolean); + + /** + * Appends and escapes the given string to this markdown string. + * @param value Plain text. + */ + appendText(value: string): MarkdownString; + + /** + * Appends the given string 'as is' to this markdown string. When [`supportThemeIcons`](#MarkdownString.supportThemeIcons) is `true`, [ThemeIcons](#ThemeIcon) in the `value` will be iconified. + * @param value Markdown string. + */ + appendMarkdown(value: string): MarkdownString; + + /** + * Appends the given string as codeblock using the provided language. + * @param value A code snippet. + * @param language An optional [language identifier](#languages.getLanguages). + */ + appendCodeblock(value: string, language?: string): MarkdownString; + } + + /** + * ~~MarkedString can be used to render human-readable text. It is either a markdown string + * or a code-block that provides a language and a code snippet. Note that + * markdown strings will be sanitized - that means html will be escaped.~~ + * + * @deprecated This type is deprecated, please use [`MarkdownString`](#MarkdownString) instead. + */ + export type MarkedString = MarkdownString | string | { language: string; value: string }; + + /** + * A hover represents additional information for a symbol or word. Hovers are + * rendered in a tooltip-like widget. + */ + export class Hover { + + /** + * The contents of this hover. + */ + contents: MarkedString[]; + + /** + * The range to which this hover applies. When missing, the + * editor will use the range at the current position or the + * current position itself. + */ + range?: Range; + + /** + * Creates a new hover object. + * + * @param contents The contents of the hover. + * @param range The range to which the hover applies. + */ + constructor(contents: MarkedString | MarkedString[], range?: Range); + } + + /** + * The hover provider interface defines the contract between extensions and + * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature. + */ + export interface HoverProvider { + + /** + * Provide a hover for the given position and document. Multiple hovers at the same + * position will be merged by the editor. A hover can have a range which defaults + * to the word range at the position when omitted. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A hover or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideHover(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * An EvaluatableExpression represents an expression in a document that can be evaluated by an active debugger or runtime. + * The result of this evaluation is shown in a tooltip-like widget. + * If only a range is specified, the expression will be extracted from the underlying document. + * An optional expression can be used to override the extracted expression. + * In this case the range is still used to highlight the range in the document. + */ + export class EvaluatableExpression { + + /* + * The range is used to extract the evaluatable expression from the underlying document and to highlight it. + */ + readonly range: Range; + + /* + * If specified the expression overrides the extracted expression. + */ + readonly expression?: string; + + /** + * Creates a new evaluatable expression object. + * + * @param range The range in the underlying document from which the evaluatable expression is extracted. + * @param expression If specified overrides the extracted expression. + */ + constructor(range: Range, expression?: string); + } + + /** + * The evaluatable expression provider interface defines the contract between extensions and + * the debug hover. In this contract the provider returns an evaluatable expression for a given position + * in a document and VS Code evaluates this expression in the active debug session and shows the result in a debug hover. + */ + export interface EvaluatableExpressionProvider { + + /** + * Provide an evaluatable expression for the given document and position. + * VS Code will evaluate this expression in the active debug session and will show the result in the debug hover. + * The expression can be implicitly specified by the range in the underlying document or by explicitly returning an expression. + * + * @param document The document for which the debug hover is about to appear. + * @param position The line and character position in the document where the debug hover is about to appear. + * @param token A cancellation token. + * @return An EvaluatableExpression or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideEvaluatableExpression(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * A document highlight kind. + */ + export enum DocumentHighlightKind { + + /** + * A textual occurrence. + */ + Text = 0, + + /** + * Read-access of a symbol, like reading a variable. + */ + Read = 1, + + /** + * Write-access of a symbol, like writing to a variable. + */ + Write = 2 + } + + /** + * A document highlight is a range inside a text document which deserves + * special attention. Usually a document highlight is visualized by changing + * the background color of its range. + */ + export class DocumentHighlight { + + /** + * The range this highlight applies to. + */ + range: Range; + + /** + * The highlight kind, default is [text](#DocumentHighlightKind.Text). + */ + kind?: DocumentHighlightKind; + + /** + * Creates a new document highlight object. + * + * @param range The range the highlight applies to. + * @param kind The highlight kind, default is [text](#DocumentHighlightKind.Text). + */ + constructor(range: Range, kind?: DocumentHighlightKind); + } + + /** + * The document highlight provider interface defines the contract between extensions and + * the word-highlight-feature. + */ + export interface DocumentHighlightProvider { + + /** + * Provide a set of document highlights, like all occurrences of a variable or + * all exit-points of a function. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentHighlights(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * A symbol kind. + */ + export enum SymbolKind { + File = 0, + Module = 1, + Namespace = 2, + Package = 3, + Class = 4, + Method = 5, + Property = 6, + Field = 7, + Constructor = 8, + Enum = 9, + Interface = 10, + Function = 11, + Variable = 12, + Constant = 13, + String = 14, + Number = 15, + Boolean = 16, + Array = 17, + Object = 18, + Key = 19, + Null = 20, + EnumMember = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25 + } + + /** + * Symbol tags are extra annotations that tweak the rendering of a symbol. + */ + export enum SymbolTag { + + /** + * Render a symbol as obsolete, usually using a strike-out. + */ + Deprecated = 1 + } + + /** + * Represents information about programming constructs like variables, classes, + * interfaces etc. + */ + export class SymbolInformation { + + /** + * The name of this symbol. + */ + name: string; + + /** + * The name of the symbol containing this symbol. + */ + containerName: string; + + /** + * The kind of this symbol. + */ + kind: SymbolKind; + + /** + * Tags for this symbol. + */ + tags?: ReadonlyArray; + + /** + * The location of this symbol. + */ + location: Location; + + /** + * Creates a new symbol information object. + * + * @param name The name of the symbol. + * @param kind The kind of the symbol. + * @param containerName The name of the symbol containing the symbol. + * @param location The location of the symbol. + */ + constructor(name: string, kind: SymbolKind, containerName: string, location: Location); + + /** + * ~~Creates a new symbol information object.~~ + * + * @deprecated Please use the constructor taking a [location](#Location) object. + * + * @param name The name of the symbol. + * @param kind The kind of the symbol. + * @param range The range of the location of the symbol. + * @param uri The resource of the location of symbol, defaults to the current document. + * @param containerName The name of the symbol containing the symbol. + */ + constructor(name: string, kind: SymbolKind, range: Range, uri?: Uri, containerName?: string); + } + + /** + * Represents programming constructs like variables, classes, interfaces etc. that appear in a document. Document + * symbols can be hierarchical and they have two ranges: one that encloses its definition and one that points to + * its most interesting range, e.g. the range of an identifier. + */ + export class DocumentSymbol { + + /** + * The name of this symbol. + */ + name: string; + + /** + * More detail for this symbol, e.g. the signature of a function. + */ + detail: string; + + /** + * The kind of this symbol. + */ + kind: SymbolKind; + + /** + * Tags for this symbol. + */ + tags?: ReadonlyArray; + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + */ + range: Range; + + /** + * The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function. + * Must be contained by the [`range`](#DocumentSymbol.range). + */ + selectionRange: Range; + + /** + * Children of this symbol, e.g. properties of a class. + */ + children: DocumentSymbol[]; + + /** + * Creates a new document symbol. + * + * @param name The name of the symbol. + * @param detail Details for the symbol. + * @param kind The kind of the symbol. + * @param range The full range of the symbol. + * @param selectionRange The range that should be reveal. + */ + constructor(name: string, detail: string, kind: SymbolKind, range: Range, selectionRange: Range); + } + + /** + * The document symbol provider interface defines the contract between extensions and + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. + */ + export interface DocumentSymbolProvider { + + /** + * Provide symbol information for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentSymbols(document: TextDocument, token: CancellationToken): ProviderResult; + } + + /** + * Metadata about a document symbol provider. + */ + export interface DocumentSymbolProviderMetadata { + /** + * A human-readable string that is shown when multiple outlines trees show for one document. + */ + label?: string; + } + + /** + * The workspace symbol provider interface defines the contract between extensions and + * the [symbol search](https://code.visualstudio.com/docs/editor/editingevolved#_open-symbol-by-name)-feature. + */ + export interface WorkspaceSymbolProvider { + + /** + * Project-wide search for a symbol matching the given query string. + * + * The `query`-parameter should be interpreted in a *relaxed way* as the editor will apply its own highlighting + * and scoring on the results. A good rule of thumb is to match case-insensitive and to simply check that the + * characters of *query* appear in their order in a candidate symbol. Don't use prefix, substring, or similar + * strict matching. + * + * To improve performance implementors can implement `resolveWorkspaceSymbol` and then provide symbols with partial + * [location](#SymbolInformation.location)-objects, without a `range` defined. The editor will then call + * `resolveWorkspaceSymbol` for selected symbols only, e.g. when opening a workspace symbol. + * + * @param query A query string, can be the empty string in which case all symbols should be returned. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideWorkspaceSymbols(query: string, token: CancellationToken): ProviderResult; + + /** + * Given a symbol fill in its [location](#SymbolInformation.location). This method is called whenever a symbol + * is selected in the UI. Providers can implement this method and return incomplete symbols from + * [`provideWorkspaceSymbols`](#WorkspaceSymbolProvider.provideWorkspaceSymbols) which often helps to improve + * performance. + * + * @param symbol The symbol that is to be resolved. Guaranteed to be an instance of an object returned from an + * earlier call to `provideWorkspaceSymbols`. + * @param token A cancellation token. + * @return The resolved symbol or a thenable that resolves to that. When no result is returned, + * the given `symbol` is used. + */ + resolveWorkspaceSymbol?(symbol: T, token: CancellationToken): ProviderResult; + } + + /** + * Value-object that contains additional information when + * requesting references. + */ + export interface ReferenceContext { + + /** + * Include the declaration of the current symbol. + */ + includeDeclaration: boolean; + } + + /** + * The reference provider interface defines the contract between extensions and + * the [find references](https://code.visualstudio.com/docs/editor/editingevolved#_peek)-feature. + */ + export interface ReferenceProvider { + + /** + * Provide a set of project-wide references for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * + * @return An array of locations or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideReferences(document: TextDocument, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult; + } + + /** + * A text edit represents edits that should be applied + * to a document. + */ + export class TextEdit { + + /** + * Utility to create a replace edit. + * + * @param range A range. + * @param newText A string. + * @return A new text edit object. + */ + static replace(range: Range, newText: string): TextEdit; + + /** + * Utility to create an insert edit. + * + * @param position A position, will become an empty range. + * @param newText A string. + * @return A new text edit object. + */ + static insert(position: Position, newText: string): TextEdit; + + /** + * Utility to create a delete edit. + * + * @param range A range. + * @return A new text edit object. + */ + static delete(range: Range): TextEdit; + + /** + * Utility to create an eol-edit. + * + * @param eol An eol-sequence + * @return A new text edit object. + */ + static setEndOfLine(eol: EndOfLine): TextEdit; + + /** + * The range this edit applies to. + */ + range: Range; + + /** + * The string this edit will insert. + */ + newText: string; + + /** + * The eol-sequence used in the document. + * + * *Note* that the eol-sequence will be applied to the + * whole document. + */ + newEol?: EndOfLine; + + /** + * Create a new TextEdit. + * + * @param range A range. + * @param newText A string. + */ + constructor(range: Range, newText: string); + } + + /** + * Additional data for entries of a workspace edit. Supports to label entries and marks entries + * as needing confirmation by the user. The editor groups edits with equal labels into tree nodes, + * for instance all edits labelled with "Changes in Strings" would be a tree node. + */ + export interface WorkspaceEditEntryMetadata { + + /** + * A flag which indicates that user confirmation is needed. + */ + needsConfirmation: boolean; + + /** + * A human-readable string which is rendered prominent. + */ + label: string; + + /** + * A human-readable string which is rendered less prominent on the same line. + */ + description?: string; + + /** + * The icon path or [ThemeIcon](#ThemeIcon) for the edit. + */ + iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + } + + /** + * A workspace edit is a collection of textual and files changes for + * multiple resources and documents. + * + * Use the [applyEdit](#workspace.applyEdit)-function to apply a workspace edit. + */ + export class WorkspaceEdit { + + /** + * The number of affected resources of textual or resource changes. + */ + readonly size: number; + + /** + * Replace the given range with given text for the given resource. + * + * @param uri A resource identifier. + * @param range A range. + * @param newText A string. + * @param metadata Optional metadata for the entry. + */ + replace(uri: Uri, range: Range, newText: string, metadata?: WorkspaceEditEntryMetadata): void; + + /** + * Insert the given text at the given position. + * + * @param uri A resource identifier. + * @param position A position. + * @param newText A string. + * @param metadata Optional metadata for the entry. + */ + insert(uri: Uri, position: Position, newText: string, metadata?: WorkspaceEditEntryMetadata): void; + + /** + * Delete the text at the given range. + * + * @param uri A resource identifier. + * @param range A range. + * @param metadata Optional metadata for the entry. + */ + delete(uri: Uri, range: Range, metadata?: WorkspaceEditEntryMetadata): void; + + /** + * Check if a text edit for a resource exists. + * + * @param uri A resource identifier. + * @return `true` if the given resource will be touched by this edit. + */ + has(uri: Uri): boolean; + + /** + * Set (and replace) text edits for a resource. + * + * @param uri A resource identifier. + * @param edits An array of text edits. + */ + set(uri: Uri, edits: TextEdit[]): void; + + /** + * Get the text edits for a resource. + * + * @param uri A resource identifier. + * @return An array of text edits. + */ + get(uri: Uri): TextEdit[]; + + /** + * Create a regular file. + * + * @param uri Uri of the new file.. + * @param options Defines if an existing file should be overwritten or be + * ignored. When overwrite and ignoreIfExists are both set overwrite wins. + * @param metadata Optional metadata for the entry. + */ + createFile(uri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; + + /** + * Delete a file or folder. + * + * @param uri The uri of the file that is to be deleted. + * @param metadata Optional metadata for the entry. + */ + deleteFile(uri: Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; + + /** + * Rename a file or folder. + * + * @param oldUri The existing file. + * @param newUri The new location. + * @param options Defines if existing files should be overwritten or be + * ignored. When overwrite and ignoreIfExists are both set overwrite wins. + * @param metadata Optional metadata for the entry. + */ + renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; + + /** + * Get all text edits grouped by resource. + * + * @return A shallow copy of `[Uri, TextEdit[]]`-tuples. + */ + entries(): [Uri, TextEdit[]][]; + } + + /** + * A snippet string is a template which allows to insert text + * and to control the editor cursor when insertion happens. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Variables are defined with `$name` and + * `${name:default value}`. The full snippet syntax is documented + * [here](https://code.visualstudio.com/docs/editor/userdefinedsnippets#_creating-your-own-snippets). + */ + export class SnippetString { + + /** + * The snippet string. + */ + value: string; + + constructor(value?: string); + + /** + * Builder-function that appends the given string to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param string A value to append 'as given'. The string will be escaped. + * @return This snippet string. + */ + appendText(string: string): SnippetString; + + /** + * Builder-function that appends a tabstop (`$1`, `$2` etc) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendTabstop(number?: number): SnippetString; + + /** + * Builder-function that appends a placeholder (`${1:value}`) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param value The value of this placeholder - either a string or a function + * with which a nested snippet can be created. + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendPlaceholder(value: string | ((snippet: SnippetString) => any), number?: number): SnippetString; + + /** + * Builder-function that appends a choice (`${1|a,b,c}`) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param values The values for choices - the array of strings + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendChoice(values: string[], number?: number): SnippetString; + + /** + * Builder-function that appends a variable (`${VAR}`) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param name The name of the variable - excluding the `$`. + * @param defaultValue The default value which is used when the variable name cannot + * be resolved - either a string or a function with which a nested snippet can be created. + * @return This snippet string. + */ + appendVariable(name: string, defaultValue: string | ((snippet: SnippetString) => any)): SnippetString; + } + + /** + * The rename provider interface defines the contract between extensions and + * the [rename](https://code.visualstudio.com/docs/editor/editingevolved#_rename-symbol)-feature. + */ + export interface RenameProvider { + + /** + * Provide an edit that describes changes that have to be made to one + * or many resources to rename a symbol to a different name. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param newName The new name of the symbol. If the given name is not valid, the provider must return a rejected promise. + * @param token A cancellation token. + * @return A workspace edit or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): ProviderResult; + + /** + * Optional function for resolving and validating a position *before* running rename. The result can + * be a range or a range and a placeholder text. The placeholder text should be the identifier of the symbol + * which is being renamed - when omitted the text in the returned range is used. + * + * *Note: * This function should throw an error or return a rejected thenable when the provided location + * doesn't allow for a rename. + * + * @param document The document in which rename will be invoked. + * @param position The position at which rename will be invoked. + * @param token A cancellation token. + * @return The range or range and placeholder text of the identifier that is to be renamed. The lack of a result can signaled by returning `undefined` or `null`. + */ + prepareRename?(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + /** + * A semantic tokens legend contains the needed information to decipher + * the integer encoded representation of semantic tokens. + */ + export class SemanticTokensLegend { + /** + * The possible token types. + */ + readonly tokenTypes: string[]; + /** + * The possible token modifiers. + */ + readonly tokenModifiers: string[]; + + constructor(tokenTypes: string[], tokenModifiers?: string[]); + } + + /** + * A semantic tokens builder can help with creating a `SemanticTokens` instance + * which contains delta encoded semantic tokens. + */ + export class SemanticTokensBuilder { + + constructor(legend?: SemanticTokensLegend); + + /** + * Add another token. + * + * @param line The token start line number (absolute value). + * @param char The token start character (absolute value). + * @param length The token length in characters. + * @param tokenType The encoded token type. + * @param tokenModifiers The encoded token modifiers. + */ + push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void; + + /** + * Add another token. Use only when providing a legend. + * + * @param range The range of the token. Must be single-line. + * @param tokenType The token type. + * @param tokenModifiers The token modifiers. + */ + push(range: Range, tokenType: string, tokenModifiers?: string[]): void; + + /** + * Finish and create a `SemanticTokens` instance. + */ + build(resultId?: string): SemanticTokens; + } + + /** + * Represents semantic tokens, either in a range or in an entire document. + * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format. + * @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to create an instance. + */ + export class SemanticTokens { + /** + * The result id of the tokens. + * + * This is the id that will be passed to `DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits` (if implemented). + */ + readonly resultId?: string; + /** + * The actual tokens data. + * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format. + */ + readonly data: Uint32Array; + + constructor(data: Uint32Array, resultId?: string); + } + + /** + * Represents edits to semantic tokens. + * @see [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format. + */ + export class SemanticTokensEdits { + /** + * The result id of the tokens. + * + * This is the id that will be passed to `DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits` (if implemented). + */ + readonly resultId?: string; + /** + * The edits to the tokens data. + * All edits refer to the initial data state. + */ + readonly edits: SemanticTokensEdit[]; + + constructor(edits: SemanticTokensEdit[], resultId?: string); + } + + /** + * Represents an edit to semantic tokens. + * @see [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format. + */ + export class SemanticTokensEdit { + /** + * The start offset of the edit. + */ + readonly start: number; + /** + * The count of elements to remove. + */ + readonly deleteCount: number; + /** + * The elements to insert. + */ + readonly data?: Uint32Array; + + constructor(start: number, deleteCount: number, data?: Uint32Array); + } + + /** + * The document semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ + export interface DocumentSemanticTokensProvider { + /** + * An optional event to signal that the semantic tokens from this provider have changed. + */ + onDidChangeSemanticTokens?: Event; + + /** + * Tokens in a file are represented as an array of integers. The position of each token is expressed relative to + * the token before it, because most tokens remain stable relative to each other when edits are made in a file. + * + * --- + * In short, each token takes 5 integers to represent, so a specific token `i` in the file consists of the following array indices: + * - at index `5*i` - `deltaLine`: token line number, relative to the previous token + * - at index `5*i+1` - `deltaStart`: token start character, relative to the previous token (relative to 0 or the previous token's start if they are on the same line) + * - at index `5*i+2` - `length`: the length of the token. A token cannot be multiline. + * - at index `5*i+3` - `tokenType`: will be looked up in `SemanticTokensLegend.tokenTypes`. We currently ask that `tokenType` < 65536. + * - at index `5*i+4` - `tokenModifiers`: each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + * + * --- + * ### How to encode tokens + * + * Here is an example for encoding a file with 3 tokens in a uint32 array: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 2, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 5, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * + * 1. First of all, a legend must be devised. This legend must be provided up-front and capture all possible token types. + * For this example, we will choose the following legend which must be passed in when registering the provider: + * ``` + * tokenTypes: ['property', 'type', 'class'], + * tokenModifiers: ['private', 'static'] + * ``` + * + * 2. The first transformation step is to encode `tokenType` and `tokenModifiers` as integers using the legend. Token types are looked + * up by index, so a `tokenType` value of `1` means `tokenTypes[1]`. Multiple token modifiers can be set by using bit flags, + * so a `tokenModifier` value of `3` is first viewed as binary `0b00000011`, which means `[tokenModifiers[0], tokenModifiers[1]]` because + * bits 0 and 1 are set. Using this legend, the tokens now are: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { line: 2, startChar: 10, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { line: 5, startChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 3. The next step is to represent each token relative to the previous token in the file. In this case, the second token + * is on the same line as the first token, so the `startChar` of the second token is made relative to the `startChar` + * of the first token, so it will be `10 - 5`. The third token is on a different line than the second token, so the + * `startChar` of the third token will not be altered: + * ``` + * { deltaLine: 2, deltaStartChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { deltaLine: 0, deltaStartChar: 5, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { deltaLine: 3, deltaStartChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 4. Finally, the last step is to inline each of the 5 fields for a token in a single array, which is a memory friendly representation: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * + * @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to encode tokens as integers. + * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. + * *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'. + */ + provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * Instead of always returning all the tokens in a file, it is possible for a `DocumentSemanticTokensProvider` to implement + * this method (`provideDocumentSemanticTokensEdits`) and then return incremental updates to the previously provided semantic tokens. + * + * --- + * ### How tokens change when the document changes + * + * Suppose that `provideDocumentSemanticTokens` has previously returned the following semantic tokens: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * + * Also suppose that after some edits, the new semantic tokens in a file are: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * It is possible to express these new tokens in terms of an edit applied to the previous tokens: + * ``` + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // old tokens + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // new tokens + * + * edit: { start: 0, deleteCount: 1, data: [3] } // replace integer at offset 0 with 3 + * ``` + * + * *NOTE*: If the provider cannot compute `SemanticTokensEdits`, it can "give up" and return all the tokens in the document again. + * *NOTE*: All edits in `SemanticTokensEdits` contain indices in the old integers array, so they all refer to the previous result state. + */ + provideDocumentSemanticTokensEdits?(document: TextDocument, previousResultId: string, token: CancellationToken): ProviderResult; + } + + /** + * The document range semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ + export interface DocumentRangeSemanticTokensProvider { + /** + * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens). + */ + provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): ProviderResult; + } + + /** + * Value-object describing what options formatting should use. + */ + export interface FormattingOptions { + + /** + * Size of a tab in spaces. + */ + tabSize: number; + + /** + * Prefer spaces over tabs. + */ + insertSpaces: boolean; + + /** + * Signature for further properties. + */ + [key: string]: boolean | number | string; + } + + /** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ + export interface DocumentFormattingEditProvider { + + /** + * Provide formatting edits for a whole document. + * + * @param document The document in which the command was invoked. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentFormattingEdits(document: TextDocument, options: FormattingOptions, token: CancellationToken): ProviderResult; + } + + /** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ + export interface DocumentRangeFormattingEditProvider { + + /** + * Provide formatting edits for a range in a document. + * + * The given range is a hint and providers can decide to format a smaller + * or larger range. Often this is done by adjusting the start and end + * of the range to full syntax nodes. + * + * @param document The document in which the command was invoked. + * @param range The range which should be formatted. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult; + } + + /** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ + export interface OnTypeFormattingEditProvider { + + /** + * Provide formatting edits after a character has been typed. + * + * The given position and character should hint to the provider + * what range the position to expand to, like find the matching `{` + * when `}` has been entered. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param ch The character that has been typed. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideOnTypeFormattingEdits(document: TextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult; + } + + /** + * Represents a parameter of a callable-signature. A parameter can + * have a label and a doc-comment. + */ + export class ParameterInformation { + + /** + * The label of this signature. + * + * Either a string or inclusive start and exclusive end offsets within its containing + * [signature label](#SignatureInformation.label). *Note*: A label of type string must be + * a substring of its containing signature information's [label](#SignatureInformation.label). + */ + label: string | [number, number]; + + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + documentation?: string | MarkdownString; + + /** + * Creates a new parameter information object. + * + * @param label A label string or inclusive start and exclusive end offsets within its containing signature label. + * @param documentation A doc string. + */ + constructor(label: string | [number, number], documentation?: string | MarkdownString); + } + + /** + * Represents the signature of something callable. A signature + * can have a label, like a function-name, a doc-comment, and + * a set of parameters. + */ + export class SignatureInformation { + + /** + * The label of this signature. Will be shown in + * the UI. + */ + label: string; + + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + documentation?: string | MarkdownString; + + /** + * The parameters of this signature. + */ + parameters: ParameterInformation[]; + + /** + * The index of the active parameter. + * + * If provided, this is used in place of [`SignatureHelp.activeSignature`](#SignatureHelp.activeSignature). + */ + activeParameter?: number; + + /** + * Creates a new signature information object. + * + * @param label A label string. + * @param documentation A doc string. + */ + constructor(label: string, documentation?: string | MarkdownString); + } + + /** + * Signature help represents the signature of something + * callable. There can be multiple signatures but only one + * active and only one active parameter. + */ + export class SignatureHelp { + + /** + * One or more signatures. + */ + signatures: SignatureInformation[]; + + /** + * The active signature. + */ + activeSignature: number; + + /** + * The active parameter of the active signature. + */ + activeParameter: number; + } + + /** + * How a [`SignatureHelpProvider`](#SignatureHelpProvider) was triggered. + */ + export enum SignatureHelpTriggerKind { + /** + * Signature help was invoked manually by the user or by a command. + */ + Invoke = 1, + + /** + * Signature help was triggered by a trigger character. + */ + TriggerCharacter = 2, + + /** + * Signature help was triggered by the cursor moving or by the document content changing. + */ + ContentChange = 3, + } + + /** + * Additional information about the context in which a + * [`SignatureHelpProvider`](#SignatureHelpProvider.provideSignatureHelp) was triggered. + */ + export interface SignatureHelpContext { + /** + * Action that caused signature help to be triggered. + */ + readonly triggerKind: SignatureHelpTriggerKind; + + /** + * Character that caused signature help to be triggered. + * + * This is `undefined` when signature help is not triggered by typing, such as when manually invoking + * signature help or when moving the cursor. + */ + readonly triggerCharacter?: string; + + /** + * `true` if signature help was already showing when it was triggered. + * + * Retriggers occur when the signature help is already active and can be caused by actions such as + * typing a trigger character, a cursor move, or document content changes. + */ + readonly isRetrigger: boolean; + + /** + * The currently active [`SignatureHelp`](#SignatureHelp). + * + * The `activeSignatureHelp` has its [`SignatureHelp.activeSignature`] field updated based on + * the user arrowing through available signatures. + */ + readonly activeSignatureHelp?: SignatureHelp; + } + + /** + * The signature help provider interface defines the contract between extensions and + * the [parameter hints](https://code.visualstudio.com/docs/editor/intellisense)-feature. + */ + export interface SignatureHelpProvider { + + /** + * Provide help for the signature at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @param context Information about how signature help was triggered. + * + * @return Signature help or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken, context: SignatureHelpContext): ProviderResult; + } + + /** + * Metadata about a registered [`SignatureHelpProvider`](#SignatureHelpProvider). + */ + export interface SignatureHelpProviderMetadata { + /** + * List of characters that trigger signature help. + */ + readonly triggerCharacters: ReadonlyArray; + + /** + * List of characters that re-trigger signature help. + * + * These trigger characters are only active when signature help is already showing. All trigger characters + * are also counted as re-trigger characters. + */ + readonly retriggerCharacters: ReadonlyArray; + } + + /** + * Completion item kinds. + */ + export enum CompletionItemKind { + Text = 0, + Method = 1, + Function = 2, + Constructor = 3, + Field = 4, + Variable = 5, + Class = 6, + Interface = 7, + Module = 8, + Property = 9, + Unit = 10, + Value = 11, + Enum = 12, + Keyword = 13, + Snippet = 14, + Color = 15, + Reference = 17, + File = 16, + Folder = 18, + EnumMember = 19, + Constant = 20, + Struct = 21, + Event = 22, + Operator = 23, + TypeParameter = 24, + User = 25, + Issue = 26, + } + + /** + * Completion item tags are extra annotations that tweak the rendering of a completion + * item. + */ + export enum CompletionItemTag { + /** + * Render a completion as obsolete, usually using a strike-out. + */ + Deprecated = 1 + } + + /** + * A completion item represents a text snippet that is proposed to complete text that is being typed. + * + * It is sufficient to create a completion item from just a [label](#CompletionItem.label). In that + * case the completion item will replace the [word](#TextDocument.getWordRangeAtPosition) + * until the cursor with the given label or [insertText](#CompletionItem.insertText). Otherwise the + * given [edit](#CompletionItem.textEdit) is used. + * + * When selecting a completion item in the editor its defined or synthesized text edit will be applied + * to *all* cursors/selections whereas [additionalTextEdits](#CompletionItem.additionalTextEdits) will be + * applied as provided. + * + * @see [CompletionItemProvider.provideCompletionItems](#CompletionItemProvider.provideCompletionItems) + * @see [CompletionItemProvider.resolveCompletionItem](#CompletionItemProvider.resolveCompletionItem) + */ + export class CompletionItem { + + /** + * The label of this completion item. By default + * this is also the text that is inserted when selecting + * this completion. + */ + label: string; + + /** + * The kind of this completion item. Based on the kind + * an icon is chosen by the editor. + */ + kind?: CompletionItemKind; + + /** + * Tags for this completion item. + */ + tags?: ReadonlyArray; + + /** + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + detail?: string; + + /** + * A human-readable string that represents a doc-comment. + */ + documentation?: string | MarkdownString; + + /** + * A string that should be used when comparing this item + * with other items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + sortText?: string; + + /** + * A string that should be used when filtering a set of + * completion items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + filterText?: string; + + /** + * Select this item when showing. *Note* that only one completion item can be selected and + * that the editor decides which item that is. The rule is that the *first* item of those + * that match best is selected. + */ + preselect?: boolean; + + /** + * A string or snippet that should be inserted in a document when selecting + * this completion. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + insertText?: string | SnippetString; + + /** + * A range or a insert and replace range selecting the text that should be replaced by this completion item. + * + * When omitted, the range of the [current word](#TextDocument.getWordRangeAtPosition) is used as replace-range + * and as insert-range the start of the [current word](#TextDocument.getWordRangeAtPosition) to the + * current position is used. + * + * *Note 1:* A range must be a [single line](#Range.isSingleLine) and it must + * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). + * *Note 2:* A insert range must be a prefix of a replace range, that means it must be contained and starting at the same position. + */ + range?: Range | { inserting: Range; replacing: Range; }; + + /** + * An optional set of characters that when pressed while this completion is active will accept it first and + * then type that character. *Note* that all commit characters should have `length=1` and that superfluous + * characters will be ignored. + */ + commitCharacters?: string[]; + + /** + * Keep whitespace of the [insertText](#CompletionItem.insertText) as is. By default, the editor adjusts leading + * whitespace of new lines so that they match the indentation of the line for which the item is accepted - setting + * this to `true` will prevent that. + */ + keepWhitespace?: boolean; + + /** + * @deprecated Use `CompletionItem.insertText` and `CompletionItem.range` instead. + * + * ~~An [edit](#TextEdit) which is applied to a document when selecting + * this completion. When an edit is provided the value of + * [insertText](#CompletionItem.insertText) is ignored.~~ + * + * ~~The [range](#Range) of the edit must be single-line and on the same + * line completions were [requested](#CompletionItemProvider.provideCompletionItems) at.~~ + */ + textEdit?: TextEdit; + + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this completion. Edits must not overlap with the main [edit](#CompletionItem.textEdit) + * nor with themselves. + */ + additionalTextEdits?: TextEdit[]; + + /** + * An optional [command](#Command) that is executed *after* inserting this completion. *Note* that + * additional modifications to the current document should be described with the + * [additionalTextEdits](#CompletionItem.additionalTextEdits)-property. + */ + command?: Command; + + /** + * Creates a new completion item. + * + * Completion items must have at least a [label](#CompletionItem.label) which then + * will be used as insert text as well as for sorting and filtering. + * + * @param label The label of the completion. + * @param kind The [kind](#CompletionItemKind) of the completion. + */ + constructor(label: string, kind?: CompletionItemKind); + } + + /** + * Represents a collection of [completion items](#CompletionItem) to be presented + * in the editor. + */ + export class CompletionList { + + /** + * This list is not complete. Further typing should result in recomputing + * this list. + */ + isIncomplete?: boolean; + + /** + * The completion items. + */ + items: T[]; + + /** + * Creates a new completion list. + * + * @param items The completion items. + * @param isIncomplete The list is not complete. + */ + constructor(items?: T[], isIncomplete?: boolean); + } + + /** + * How a [completion provider](#CompletionItemProvider) was triggered + */ + export enum CompletionTriggerKind { + /** + * Completion was triggered normally. + */ + Invoke = 0, + /** + * Completion was triggered by a trigger character. + */ + TriggerCharacter = 1, + /** + * Completion was re-triggered as current completion list is incomplete + */ + TriggerForIncompleteCompletions = 2 + } + + /** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ + export interface CompletionContext { + /** + * How the completion was triggered. + */ + readonly triggerKind: CompletionTriggerKind; + + /** + * Character that triggered the completion item provider. + * + * `undefined` if provider was not triggered by a character. + * + * The trigger character is already in the document when the completion provider is triggered. + */ + readonly triggerCharacter?: string; + } + + /** + * The completion item provider interface defines the contract between extensions and + * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). + * + * Providers can delay the computation of the [`detail`](#CompletionItem.detail) + * and [`documentation`](#CompletionItem.documentation) properties by implementing the + * [`resolveCompletionItem`](#CompletionItemProvider.resolveCompletionItem)-function. However, properties that + * are needed for the initial sorting and filtering, like `sortText`, `filterText`, `insertText`, and `range`, must + * not be changed during resolve. + * + * Providers are asked for completions either explicitly by a user gesture or -depending on the configuration- + * implicitly when typing words or trigger characters. + */ + export interface CompletionItemProvider { + + /** + * Provide completion items for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @param context How the completion was triggered. + * + * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken, context: CompletionContext): ProviderResult>; + + /** + * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) + * or [details](#CompletionItem.detail). + * + * The editor will only resolve a completion item once. + * + * *Note* that this function is called when completion items are already showing in the UI or when an item has been + * selected for insertion. Because of that, no property that changes the presentation (label, sorting, filtering etc) + * or the (primary) insert behaviour ([insertText](#CompletionItem.insertText)) can be changed. + * + * This function may fill in [additionalTextEdits](#CompletionItem.additionalTextEdits). However, that means an item might be + * inserted *before* resolving is done and in that case the editor will do a best effort to still apply those additional + * text edits. + * + * @param item A completion item currently active in the UI. + * @param token A cancellation token. + * @return The resolved completion item or a thenable that resolves to of such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveCompletionItem?(item: T, token: CancellationToken): ProviderResult; + } + + /** + * A document link is a range in a text document that links to an internal or external resource, like another + * text document or a web site. + */ + export class DocumentLink { + + /** + * The range this link applies to. + */ + range: Range; + + /** + * The uri this link points to. + */ + target?: Uri; + + /** + * The tooltip text when you hover over this link. + * + * If a tooltip is provided, is will be displayed in a string that includes instructions on how to + * trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + * user settings, and localization. + */ + tooltip?: string; + + /** + * Creates a new document link. + * + * @param range The range the document link applies to. Must not be empty. + * @param target The uri the document link points to. + */ + constructor(range: Range, target?: Uri); + } + + /** + * The document link provider defines the contract between extensions and feature of showing + * links in the editor. + */ + export interface DocumentLinkProvider { + + /** + * Provide links for the given document. Note that the editor ships with a default provider that detects + * `http(s)` and `file` links. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [document links](#DocumentLink) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentLinks(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * Given a link fill in its [target](#DocumentLink.target). This method is called when an incomplete + * link is selected in the UI. Providers can implement this method and return incomplete links + * (without target) from the [`provideDocumentLinks`](#DocumentLinkProvider.provideDocumentLinks) method which + * often helps to improve performance. + * + * @param link The link that is to be resolved. + * @param token A cancellation token. + */ + resolveDocumentLink?(link: T, token: CancellationToken): ProviderResult; + } + + /** + * Represents a color in RGBA space. + */ + export class Color { + + /** + * The red component of this color in the range [0-1]. + */ + readonly red: number; + + /** + * The green component of this color in the range [0-1]. + */ + readonly green: number; + + /** + * The blue component of this color in the range [0-1]. + */ + readonly blue: number; + + /** + * The alpha component of this color in the range [0-1]. + */ + readonly alpha: number; + + /** + * Creates a new color instance. + * + * @param red The red component. + * @param green The green component. + * @param blue The blue component. + * @param alpha The alpha component. + */ + constructor(red: number, green: number, blue: number, alpha: number); + } + + /** + * Represents a color range from a document. + */ + export class ColorInformation { + + /** + * The range in the document where this color appears. + */ + range: Range; + + /** + * The actual color value for this color range. + */ + color: Color; + + /** + * Creates a new color range. + * + * @param range The range the color appears in. Must not be empty. + * @param color The value of the color. + * @param format The format in which this color is currently formatted. + */ + constructor(range: Range, color: Color); + } + + /** + * A color presentation object describes how a [`color`](#Color) should be represented as text and what + * edits are required to refer to it from source code. + * + * For some languages one color can have multiple presentations, e.g. css can represent the color red with + * the constant `Red`, the hex-value `#ff0000`, or in rgba and hsla forms. In csharp other representations + * apply, e.g. `System.Drawing.Color.Red`. + */ + export class ColorPresentation { + + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + label: string; + + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * is used. + */ + textEdit?: TextEdit; + + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + */ + additionalTextEdits?: TextEdit[]; + + /** + * Creates a new color presentation. + * + * @param label The label of this color presentation. + */ + constructor(label: string); + } + + /** + * The document color provider defines the contract between extensions and feature of + * picking and modifying colors in the editor. + */ + export interface DocumentColorProvider { + + /** + * Provide colors for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [color information](#ColorInformation) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * Provide [representations](#ColorPresentation) for a color. + * + * @param color The color to show and insert. + * @param context A context object with additional information + * @param token A cancellation token. + * @return An array of color presentations or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideColorPresentations(color: Color, context: { document: TextDocument, range: Range }, token: CancellationToken): ProviderResult; + } + + /** + * A line based folding range. To be valid, start and end line must be bigger than zero and smaller than the number of lines in the document. + * Invalid ranges will be ignored. + */ + export class FoldingRange { + + /** + * The zero-based start line of the range to fold. The folded area starts after the line's last character. + * To be valid, the end must be zero or larger and smaller than the number of lines in the document. + */ + start: number; + + /** + * The zero-based end line of the range to fold. The folded area ends with the line's last character. + * To be valid, the end must be zero or larger and smaller than the number of lines in the document. + */ + end: number; + + /** + * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or + * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands + * like 'Fold all comments'. See + * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of all kinds. + * If not set, the range is originated from a syntax element. + */ + kind?: FoldingRangeKind; + + /** + * Creates a new folding range. + * + * @param start The start line of the folded range. + * @param end The end line of the folded range. + * @param kind The kind of the folding range. + */ + constructor(start: number, end: number, kind?: FoldingRangeKind); + } + + /** + * An enumeration of specific folding range kinds. The kind is an optional field of a [FoldingRange](#FoldingRange) + * and is used to distinguish specific folding ranges such as ranges originated from comments. The kind is used by commands like + * `Fold all comments` or `Fold all regions`. + * If the kind is not set on the range, the range originated from a syntax element other than comments, imports or region markers. + */ + export enum FoldingRangeKind { + /** + * Kind for folding range representing a comment. + */ + Comment = 1, + /** + * Kind for folding range representing a import. + */ + Imports = 2, + /** + * Kind for folding range representing regions originating from folding markers like `#region` and `#endregion`. + */ + Region = 3 + } + + /** + * Folding context (for future use) + */ + export interface FoldingContext { + } + + /** + * The folding range provider interface defines the contract between extensions and + * [Folding](https://code.visualstudio.com/docs/editor/codebasics#_folding) in the editor. + */ + export interface FoldingRangeProvider { + /** + * Returns a list of folding ranges or null and undefined if the provider + * does not want to participate or was cancelled. + * @param document The document in which the command was invoked. + * @param context Additional context information (for future use) + * @param token A cancellation token. + */ + provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken): ProviderResult; + } + + /** + * A selection range represents a part of a selection hierarchy. A selection range + * may have a parent selection range that contains it. + */ + export class SelectionRange { + + /** + * The [range](#Range) of this selection range. + */ + range: Range; + + /** + * The parent selection range containing this range. + */ + parent?: SelectionRange; + + /** + * Creates a new selection range. + * + * @param range The range of the selection range. + * @param parent The parent of the selection range. + */ + constructor(range: Range, parent?: SelectionRange); + } + + export interface SelectionRangeProvider { + /** + * Provide selection ranges for the given positions. + * + * Selection ranges should be computed individually and independent for each position. The editor will merge + * and deduplicate ranges but providers must return hierarchies of selection ranges so that a range + * is [contained](#Range.contains) by its parent. + * + * @param document The document in which the command was invoked. + * @param positions The positions at which the command was invoked. + * @param token A cancellation token. + * @return Selection ranges or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideSelectionRanges(document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult; + } + + /** + * Represents programming constructs like functions or constructors in the context + * of call hierarchy. + */ + export class CallHierarchyItem { + /** + * The name of this item. + */ + name: string; + + /** + * The kind of this item. + */ + kind: SymbolKind; + + /** + * Tags for this item. + */ + tags?: ReadonlyArray; + + /** + * More detail for this item, e.g. the signature of a function. + */ + detail?: string; + + /** + * The resource identifier of this item. + */ + uri: Uri; + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + */ + range: Range; + + /** + * The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. + * Must be contained by the [`range`](#CallHierarchyItem.range). + */ + selectionRange: Range; + + /** + * Creates a new call hierarchy item. + */ + constructor(kind: SymbolKind, name: string, detail: string, uri: Uri, range: Range, selectionRange: Range); + } + + /** + * Represents an incoming call, e.g. a caller of a method or constructor. + */ + export class CallHierarchyIncomingCall { + + /** + * The item that makes the call. + */ + from: CallHierarchyItem; + + /** + * The range at which at which the calls appears. This is relative to the caller + * denoted by [`this.from`](#CallHierarchyIncomingCall.from). + */ + fromRanges: Range[]; + + /** + * Create a new call object. + * + * @param item The item making the call. + * @param fromRanges The ranges at which the calls appear. + */ + constructor(item: CallHierarchyItem, fromRanges: Range[]); + } + + /** + * Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. + */ + export class CallHierarchyOutgoingCall { + + /** + * The item that is called. + */ + to: CallHierarchyItem; + + /** + * The range at which this item is called. This is the range relative to the caller, e.g the item + * passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyProvider.provideCallHierarchyOutgoingCalls) + * and not [`this.to`](#CallHierarchyOutgoingCall.to). + */ + fromRanges: Range[]; + + /** + * Create a new call object. + * + * @param item The item being called + * @param fromRanges The ranges at which the calls appear. + */ + constructor(item: CallHierarchyItem, fromRanges: Range[]); + } + + /** + * The call hierarchy provider interface describes the contract between extensions + * and the call hierarchy feature which allows to browse calls and caller of function, + * methods, constructor etc. + */ + export interface CallHierarchyProvider { + + /** + * Bootstraps call hierarchy by returning the item that is denoted by the given document + * and position. This item will be used as entry into the call graph. Providers should + * return `undefined` or `null` when there is no item at the given location. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @returns A call hierarchy item or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + prepareCallHierarchy(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + + /** + * Provide all incoming calls for an item, e.g all callers for a method. In graph terms this describes directed + * and annotated edges inside the call graph, e.g the given item is the starting node and the result is the nodes + * that can be reached. + * + * @param item The hierarchy item for which incoming calls should be computed. + * @param token A cancellation token. + * @returns A set of incoming calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult; + + /** + * Provide all outgoing calls for an item, e.g call calls to functions, methods, or constructors from the given item. In + * graph terms this describes directed and annotated edges inside the call graph, e.g the given item is the starting + * node and the result is the nodes that can be reached. + * + * @param item The hierarchy item for which outgoing calls should be computed. + * @param token A cancellation token. + * @returns A set of outgoing calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult; + } + + /** + * A tuple of two characters, like a pair of + * opening and closing brackets. + */ + export type CharacterPair = [string, string]; + + /** + * Describes how comments for a language work. + */ + export interface CommentRule { + + /** + * The line comment token, like `// this is a comment` + */ + lineComment?: string; + + /** + * The block comment character pair, like `/* block comment */` + */ + blockComment?: CharacterPair; + } + + /** + * Describes indentation rules for a language. + */ + export interface IndentationRule { + /** + * If a line matches this pattern, then all the lines after it should be unindented once (until another rule matches). + */ + decreaseIndentPattern: RegExp; + /** + * If a line matches this pattern, then all the lines after it should be indented once (until another rule matches). + */ + increaseIndentPattern: RegExp; + /** + * If a line matches this pattern, then **only the next line** after it should be indented once. + */ + indentNextLinePattern?: RegExp; + /** + * If a line matches this pattern, then its indentation should not be changed and it should not be evaluated against the other rules. + */ + unIndentedLinePattern?: RegExp; + } + + /** + * Describes what to do with the indentation when pressing Enter. + */ + export enum IndentAction { + /** + * Insert new line and copy the previous line's indentation. + */ + None = 0, + /** + * Insert new line and indent once (relative to the previous line's indentation). + */ + Indent = 1, + /** + * Insert two new lines: + * - the first one indented which will hold the cursor + * - the second one at the same indentation level + */ + IndentOutdent = 2, + /** + * Insert new line and outdent once (relative to the previous line's indentation). + */ + Outdent = 3 + } + + /** + * Describes what to do when pressing Enter. + */ + export interface EnterAction { + /** + * Describe what to do with the indentation. + */ + indentAction: IndentAction; + /** + * Describes text to be appended after the new line and after the indentation. + */ + appendText?: string; + /** + * Describes the number of characters to remove from the new line's indentation. + */ + removeText?: number; + } + + /** + * Describes a rule to be evaluated when pressing Enter. + */ + export interface OnEnterRule { + /** + * This rule will only execute if the text before the cursor matches this regular expression. + */ + beforeText: RegExp; + /** + * This rule will only execute if the text after the cursor matches this regular expression. + */ + afterText?: RegExp; + /** + * The action to execute. + */ + action: EnterAction; + } + + /** + * The language configuration interfaces defines the contract between extensions + * and various editor features, like automatic bracket insertion, automatic indentation etc. + */ + export interface LanguageConfiguration { + /** + * The language's comment settings. + */ + comments?: CommentRule; + /** + * The language's brackets. + * This configuration implicitly affects pressing Enter around these brackets. + */ + brackets?: CharacterPair[]; + /** + * The language's word definition. + * If the language supports Unicode identifiers (e.g. JavaScript), it is preferable + * to provide a word definition that uses exclusion of known separators. + * e.g.: A regex that matches anything except known separators (and dot is allowed to occur in a floating point number): + * /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g + */ + wordPattern?: RegExp; + /** + * The language's indentation settings. + */ + indentationRules?: IndentationRule; + /** + * The language's rules to be evaluated when pressing Enter. + */ + onEnterRules?: OnEnterRule[]; + + /** + * **Deprecated** Do not use. + * + * @deprecated Will be replaced by a better API soon. + */ + __electricCharacterSupport?: { + /** + * This property is deprecated and will be **ignored** from + * the editor. + * @deprecated + */ + brackets?: any; + /** + * This property is deprecated and not fully supported anymore by + * the editor (scope and lineStart are ignored). + * Use the autoClosingPairs property in the language configuration file instead. + * @deprecated + */ + docComment?: { + scope: string; + open: string; + lineStart: string; + close?: string; + }; + }; + + /** + * **Deprecated** Do not use. + * + * @deprecated * Use the autoClosingPairs property in the language configuration file instead. + */ + __characterPairSupport?: { + autoClosingPairs: { + open: string; + close: string; + notIn?: string[]; + }[]; + }; + } + + /** + * The configuration target + */ + export enum ConfigurationTarget { + /** + * Global configuration + */ + Global = 1, + + /** + * Workspace configuration + */ + Workspace = 2, + + /** + * Workspace folder configuration + */ + WorkspaceFolder = 3 + } + + /** + * Represents the configuration. It is a merged view of + * + * - *Default Settings* + * - *Global (User) Settings* + * - *Workspace settings* + * - *Workspace Folder settings* - From one of the [Workspace Folders](#workspace.workspaceFolders) under which requested resource belongs to. + * - *Language settings* - Settings defined under requested language. + * + * The *effective* value (returned by [`get`](#WorkspaceConfiguration.get)) is computed by overriding or merging the values in the following order. + * + * ``` + * `defaultValue` + * `globalValue` (if defined) + * `workspaceValue` (if defined) + * `workspaceFolderValue` (if defined) + * `defaultLanguageValue` (if defined) + * `globalLanguageValue` (if defined) + * `workspaceLanguageValue` (if defined) + * `workspaceFolderLanguageValue` (if defined) + * ``` + * **Note:** Only `object` value types are merged and all other value types are overridden. + * + * Example 1: Overriding + * + * ```ts + * defaultValue = 'on'; + * globalValue = 'relative' + * workspaceFolderValue = 'off' + * value = 'off' + * ``` + * + * Example 2: Language Values + * + * ```ts + * defaultValue = 'on'; + * globalValue = 'relative' + * workspaceFolderValue = 'off' + * globalLanguageValue = 'on' + * value = 'on' + * ``` + * + * Example 3: Object Values + * + * ```ts + * defaultValue = { "a": 1, "b": 2 }; + * globalValue = { "b": 3, "c": 4 }; + * value = { "a": 1, "b": 3, "c": 4 }; + * ``` + * + * *Note:* Workspace and Workspace Folder configurations contains `launch` and `tasks` settings. Their basename will be + * part of the section identifier. The following snippets shows how to retrieve all configurations + * from `launch.json`: + * + * ```ts + * // launch.json configuration + * const config = workspace.getConfiguration('launch', vscode.workspace.workspaceFolders[0].uri); + * + * // retrieve values + * const values = config.get('configurations'); + * ``` + * + * Refer to [Settings](https://code.visualstudio.com/docs/getstarted/settings) for more information. + */ + export interface WorkspaceConfiguration { + + /** + * Return a value from this configuration. + * + * @param section Configuration name, supports _dotted_ names. + * @return The value `section` denotes or `undefined`. + */ + get(section: string): T | undefined; + + /** + * Return a value from this configuration. + * + * @param section Configuration name, supports _dotted_ names. + * @param defaultValue A value should be returned when no value could be found, is `undefined`. + * @return The value `section` denotes or the default. + */ + get(section: string, defaultValue: T): T; + + /** + * Check if this configuration has a certain value. + * + * @param section Configuration name, supports _dotted_ names. + * @return `true` if the section doesn't resolve to `undefined`. + */ + has(section: string): boolean; + + /** + * Retrieve all information about a configuration setting. A configuration value + * often consists of a *default* value, a global or installation-wide value, + * a workspace-specific value, folder-specific value + * and language-specific values (if [WorkspaceConfiguration](#WorkspaceConfiguration) is scoped to a language). + * + * Also provides all language ids under which the given configuration setting is defined. + * + * *Note:* The configuration name must denote a leaf in the configuration tree + * (`editor.fontSize` vs `editor`) otherwise no result is returned. + * + * @param section Configuration name, supports _dotted_ names. + * @return Information about a configuration setting or `undefined`. + */ + inspect(section: string): { + key: string; + + defaultValue?: T; + globalValue?: T; + workspaceValue?: T, + workspaceFolderValue?: T, + + defaultLanguageValue?: T; + globalLanguageValue?: T; + workspaceLanguageValue?: T; + workspaceFolderLanguageValue?: T; + + languageIds?: string[]; + + } | undefined; + + /** + * Update a configuration value. The updated configuration values are persisted. + * + * A value can be changed in + * + * - [Global settings](#ConfigurationTarget.Global): Changes the value for all instances of the editor. + * - [Workspace settings](#ConfigurationTarget.Workspace): Changes the value for current workspace, if available. + * - [Workspace folder settings](#ConfigurationTarget.WorkspaceFolder): Changes the value for settings from one of the [Workspace Folders](#workspace.workspaceFolders) under which the requested resource belongs to. + * - Language settings: Changes the value for the requested languageId. + * + * *Note:* To remove a configuration value use `undefined`, like so: `config.update('somekey', undefined)` + * + * @param section Configuration name, supports _dotted_ names. + * @param value The new value. + * @param configurationTarget The [configuration target](#ConfigurationTarget) or a boolean value. + * - If `true` updates [Global settings](#ConfigurationTarget.Global). + * - If `false` updates [Workspace settings](#ConfigurationTarget.Workspace). + * - If `undefined` or `null` updates to [Workspace folder settings](#ConfigurationTarget.WorkspaceFolder) if configuration is resource specific, + * otherwise to [Workspace settings](#ConfigurationTarget.Workspace). + * @param overrideInLanguage Whether to update the value in the scope of requested languageId or not. + * - If `true` updates the value under the requested languageId. + * - If `undefined` updates the value under the requested languageId only if the configuration is defined for the language. + * @throws error while updating + * - configuration which is not registered. + * - window configuration to workspace folder + * - configuration to workspace or workspace folder when no workspace is opened. + * - configuration to workspace folder when there is no workspace folder settings. + * - configuration to workspace folder when [WorkspaceConfiguration](#WorkspaceConfiguration) is not scoped to a resource. + */ + update(section: string, value: any, configurationTarget?: ConfigurationTarget | boolean, overrideInLanguage?: boolean): Thenable; + + /** + * Readable dictionary that backs this configuration. + */ + readonly [key: string]: any; + } + + /** + * Represents a location inside a resource, such as a line + * inside a text file. + */ + export class Location { + + /** + * The resource identifier of this location. + */ + uri: Uri; + + /** + * The document range of this location. + */ + range: Range; + + /** + * Creates a new location object. + * + * @param uri The resource identifier. + * @param rangeOrPosition The range or position. Positions will be converted to an empty range. + */ + constructor(uri: Uri, rangeOrPosition: Range | Position); + } + + /** + * Represents the connection of two locations. Provides additional metadata over normal [locations](#Location), + * including an origin range. + */ + export interface LocationLink { + /** + * Span of the origin of this link. + * + * Used as the underlined span for mouse definition hover. Defaults to the word range at + * the definition position. + */ + originSelectionRange?: Range; + + /** + * The target resource identifier of this link. + */ + targetUri: Uri; + + /** + * The full target range of this link. + */ + targetRange: Range; + + /** + * The span of this link. + */ + targetSelectionRange?: Range; + } + + /** + * The event that is fired when diagnostics change. + */ + export interface DiagnosticChangeEvent { + + /** + * An array of resources for which diagnostics have changed. + */ + readonly uris: ReadonlyArray; + } + + /** + * Represents the severity of diagnostics. + */ + export enum DiagnosticSeverity { + + /** + * Something not allowed by the rules of a language or other means. + */ + Error = 0, + + /** + * Something suspicious but allowed. + */ + Warning = 1, + + /** + * Something to inform about but not a problem. + */ + Information = 2, + + /** + * Something to hint to a better way of doing it, like proposing + * a refactoring. + */ + Hint = 3 + } + + /** + * Represents a related message and source code location for a diagnostic. This should be + * used to point to code locations that cause or related to a diagnostics, e.g. when duplicating + * a symbol in a scope. + */ + export class DiagnosticRelatedInformation { + + /** + * The location of this related diagnostic information. + */ + location: Location; + + /** + * The message of this related diagnostic information. + */ + message: string; + + /** + * Creates a new related diagnostic information object. + * + * @param location The location. + * @param message The message. + */ + constructor(location: Location, message: string); + } + + /** + * Additional metadata about the type of a diagnostic. + */ + export enum DiagnosticTag { + /** + * Unused or unnecessary code. + * + * Diagnostics with this tag are rendered faded out. The amount of fading + * is controlled by the `"editorUnnecessaryCode.opacity"` theme color. For + * example, `"editorUnnecessaryCode.opacity": "#000000c0"` will render the + * code with 75% opacity. For high contrast themes, use the + * `"editorUnnecessaryCode.border"` theme color to underline unnecessary code + * instead of fading it out. + */ + Unnecessary = 1, + + /** + * Deprecated or obsolete code. + * + * Diagnostics with this tag are rendered with a strike through. + */ + Deprecated = 2, + } + + /** + * Represents a diagnostic, such as a compiler error or warning. Diagnostic objects + * are only valid in the scope of a file. + */ + export class Diagnostic { + + /** + * The range to which this diagnostic applies. + */ + range: Range; + + /** + * The human-readable message. + */ + message: string; + + /** + * The severity, default is [error](#DiagnosticSeverity.Error). + */ + severity: DiagnosticSeverity; + + /** + * A human-readable string describing the source of this + * diagnostic, e.g. 'typescript' or 'super lint'. + */ + source?: string; + + /** + * A code or identifier for this diagnostic. + * Should be used for later processing, e.g. when providing [code actions](#CodeActionContext). + */ + code?: string | number | { + /** + * A code or identifier for this diagnostic. + * Should be used for later processing, e.g. when providing [code actions](#CodeActionContext). + */ + value: string | number; + + /** + * A target URI to open with more information about the diagnostic error. + */ + target: Uri; + }; + + /** + * An array of related diagnostic information, e.g. when symbol-names within + * a scope collide all definitions can be marked via this property. + */ + relatedInformation?: DiagnosticRelatedInformation[]; + + /** + * Additional metadata about the diagnostic. + */ + tags?: DiagnosticTag[]; + + /** + * Creates a new diagnostic object. + * + * @param range The range to which this diagnostic applies. + * @param message The human-readable message. + * @param severity The severity, default is [error](#DiagnosticSeverity.Error). + */ + constructor(range: Range, message: string, severity?: DiagnosticSeverity); + } + + /** + * A diagnostics collection is a container that manages a set of + * [diagnostics](#Diagnostic). Diagnostics are always scopes to a + * diagnostics collection and a resource. + * + * To get an instance of a `DiagnosticCollection` use + * [createDiagnosticCollection](#languages.createDiagnosticCollection). + */ + export interface DiagnosticCollection { + + /** + * The name of this diagnostic collection, for instance `typescript`. Every diagnostic + * from this collection will be associated with this name. Also, the task framework uses this + * name when defining [problem matchers](https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher). + */ + readonly name: string; + + /** + * Assign diagnostics for given resource. Will replace + * existing diagnostics for that resource. + * + * @param uri A resource identifier. + * @param diagnostics Array of diagnostics or `undefined` + */ + set(uri: Uri, diagnostics: ReadonlyArray | undefined): void; + + /** + * Replace all entries in this collection. + * + * Diagnostics of multiple tuples of the same uri will be merged, e.g + * `[[file1, [d1]], [file1, [d2]]]` is equivalent to `[[file1, [d1, d2]]]`. + * If a diagnostics item is `undefined` as in `[file1, undefined]` + * all previous but not subsequent diagnostics are removed. + * + * @param entries An array of tuples, like `[[file1, [d1, d2]], [file2, [d3, d4, d5]]]`, or `undefined`. + */ + set(entries: ReadonlyArray<[Uri, ReadonlyArray | undefined]>): void; + + /** + * Remove all diagnostics from this collection that belong + * to the provided `uri`. The same as `#set(uri, undefined)`. + * + * @param uri A resource identifier. + */ + delete(uri: Uri): void; + + /** + * Remove all diagnostics from this collection. The same + * as calling `#set(undefined)`; + */ + clear(): void; + + /** + * Iterate over each entry in this collection. + * + * @param callback Function to execute for each entry. + * @param thisArg The `this` context used when invoking the handler function. + */ + forEach(callback: (uri: Uri, diagnostics: ReadonlyArray, collection: DiagnosticCollection) => any, thisArg?: any): void; + + /** + * Get the diagnostics for a given resource. *Note* that you cannot + * modify the diagnostics-array returned from this call. + * + * @param uri A resource identifier. + * @returns An immutable array of [diagnostics](#Diagnostic) or `undefined`. + */ + get(uri: Uri): ReadonlyArray | undefined; + + /** + * Check if this collection contains diagnostics for a + * given resource. + * + * @param uri A resource identifier. + * @returns `true` if this collection has diagnostic for the given resource. + */ + has(uri: Uri): boolean; + + /** + * Dispose and free associated resources. Calls + * [clear](#DiagnosticCollection.clear). + */ + dispose(): void; + } + + /** + * Denotes a location of an editor in the window. Editors can be arranged in a grid + * and each column represents one editor location in that grid by counting the editors + * in order of their appearance. + */ + export enum ViewColumn { + /** + * A *symbolic* editor column representing the currently active column. This value + * can be used when opening editors, but the *resolved* [viewColumn](#TextEditor.viewColumn)-value + * of editors will always be `One`, `Two`, `Three`,... or `undefined` but never `Active`. + */ + Active = -1, + /** + * A *symbolic* editor column representing the column to the side of the active one. This value + * can be used when opening editors, but the *resolved* [viewColumn](#TextEditor.viewColumn)-value + * of editors will always be `One`, `Two`, `Three`,... or `undefined` but never `Beside`. + */ + Beside = -2, + /** + * The first editor column. + */ + One = 1, + /** + * The second editor column. + */ + Two = 2, + /** + * The third editor column. + */ + Three = 3, + /** + * The fourth editor column. + */ + Four = 4, + /** + * The fifth editor column. + */ + Five = 5, + /** + * The sixth editor column. + */ + Six = 6, + /** + * The seventh editor column. + */ + Seven = 7, + /** + * The eighth editor column. + */ + Eight = 8, + /** + * The ninth editor column. + */ + Nine = 9 + } + + /** + * An output channel is a container for readonly textual information. + * + * To get an instance of an `OutputChannel` use + * [createOutputChannel](#window.createOutputChannel). + */ + export interface OutputChannel { + + /** + * The human-readable name of this output channel. + */ + readonly name: string; + + /** + * Append the given value to the channel. + * + * @param value A string, falsy values will not be printed. + */ + append(value: string): void; + + /** + * Append the given value and a line feed character + * to the channel. + * + * @param value A string, falsy values will be printed. + */ + appendLine(value: string): void; + + /** + * Removes all output from the channel. + */ + clear(): void; + + /** + * Reveal this channel in the UI. + * + * @param preserveFocus When `true` the channel will not take focus. + */ + show(preserveFocus?: boolean): void; + + /** + * ~~Reveal this channel in the UI.~~ + * + * @deprecated Use the overload with just one parameter (`show(preserveFocus?: boolean): void`). + * + * @param column This argument is **deprecated** and will be ignored. + * @param preserveFocus When `true` the channel will not take focus. + */ + show(column?: ViewColumn, preserveFocus?: boolean): void; + + /** + * Hide this channel from the UI. + */ + hide(): void; + + /** + * Dispose and free associated resources. + */ + dispose(): void; + } + + /** + * Accessibility information which controls screen reader behavior. + */ + export interface AccessibilityInformation { + /** + * Label to be read out by a screen reader once the item has focus. + */ + label: string; + + /** + * Role of the widget which defines how a screen reader interacts with it. + * The role should be set in special cases when for example a tree-like element behaves like a checkbox. + * If role is not specified VS Code will pick the appropriate role automatically. + * More about aria roles can be found here https://w3c.github.io/aria/#widget_roles + */ + role?: string; + } + + /** + * Represents the alignment of status bar items. + */ + export enum StatusBarAlignment { + + /** + * Aligned to the left side. + */ + Left = 1, + + /** + * Aligned to the right side. + */ + Right = 2 + } + + /** + * A status bar item is a status bar contribution that can + * show text and icons and run a command on click. + */ + export interface StatusBarItem { + + /** + * The alignment of this item. + */ + readonly alignment: StatusBarAlignment; + + /** + * The priority of this item. Higher value means the item should + * be shown more to the left. + */ + readonly priority?: number; + + /** + * The text to show for the entry. You can embed icons in the text by leveraging the syntax: + * + * `My text $(icon-name) contains icons like $(icon-name) this one.` + * + * Where the icon-name is taken from the [codicon](https://microsoft.github.io/vscode-codicons/dist/codicon.html) icon set, e.g. + * `light-bulb`, `thumbsup`, `zap` etc. + */ + text: string; + + /** + * The tooltip text when you hover over this entry. + */ + tooltip: string | undefined; + + /** + * The foreground color for this entry. + */ + color: string | ThemeColor | undefined; + + /** + * [`Command`](#Command) or identifier of a command to run on click. + * + * The command must be [known](#commands.getCommands). + * + * Note that if this is a [`Command`](#Command) object, only the [`command`](#Command.command) and [`arguments`](#Command.arguments) + * are used by VS Code. + */ + command: string | Command | undefined; + + /** + * Accessibility information used when screen reader interacts with this StatusBar item + */ + accessibilityInformation?: AccessibilityInformation; + + /** + * Shows the entry in the status bar. + */ + show(): void; + + /** + * Hide the entry in the status bar. + */ + hide(): void; + + /** + * Dispose and free associated resources. Call + * [hide](#StatusBarItem.hide). + */ + dispose(): void; + } + + /** + * Defines a generalized way of reporting progress updates. + */ + export interface Progress { + + /** + * Report a progress update. + * @param value A progress item, like a message and/or an + * report on how much work finished + */ + report(value: T): void; + } + + /** + * An individual terminal instance within the integrated terminal. + */ + export interface Terminal { + + /** + * The name of the terminal. + */ + readonly name: string; + + /** + * The process ID of the shell process. + */ + readonly processId: Thenable; + + /** + * The object used to initialize the terminal, this is useful for example to detecting the + * shell type of when the terminal was not launched by this extension or for detecting what + * folder the shell was launched in. + */ + readonly creationOptions: Readonly; + + /** + * The exit status of the terminal, this will be undefined while the terminal is active. + * + * **Example:** Show a notification with the exit code when the terminal exits with a + * non-zero exit code. + * ```typescript + * window.onDidCloseTerminal(t => { + * if (t.exitStatus && t.exitStatus.code) { + * vscode.window.showInformationMessage(`Exit code: ${t.exitStatus.code}`); + * } + * }); + * ``` + */ + readonly exitStatus: TerminalExitStatus | undefined; + + /** + * Send text to the terminal. The text is written to the stdin of the underlying pty process + * (shell) of the terminal. + * + * @param text The text to send. + * @param addNewLine Whether to add a new line to the text being sent, this is normally + * required to run a command in the terminal. The character(s) added are \n or \r\n + * depending on the platform. This defaults to `true`. + */ + sendText(text: string, addNewLine?: boolean): void; + + /** + * Show the terminal panel and reveal this terminal in the UI. + * + * @param preserveFocus When `true` the terminal will not take focus. + */ + show(preserveFocus?: boolean): void; + + /** + * Hide the terminal panel if this terminal is currently showing. + */ + hide(): void; + + /** + * Dispose and free associated resources. + */ + dispose(): void; + } + + /** + * In a remote window the extension kind describes if an extension + * runs where the UI (window) runs or if an extension runs remotely. + */ + export enum ExtensionKind { + + /** + * Extension runs where the UI runs. + */ + UI = 1, + + /** + * Extension runs where the remote extension host runs. + */ + Workspace = 2 + } + + /** + * Represents an extension. + * + * To get an instance of an `Extension` use [getExtension](#extensions.getExtension). + */ + export interface Extension { + + /** + * The canonical extension identifier in the form of: `publisher.name`. + */ + readonly id: string; + + /** + * The uri of the directory containing the extension. + */ + readonly extensionUri: Uri; + + /** + * The absolute file path of the directory containing this extension. Shorthand + * notation for [Extension.extensionUri.fsPath](#Extension.extensionUri) (independent of the uri scheme). + */ + readonly extensionPath: string; + + /** + * `true` if the extension has been activated. + */ + readonly isActive: boolean; + + /** + * The parsed contents of the extension's package.json. + */ + readonly packageJSON: any; + + /** + * The extension kind describes if an extension runs where the UI runs + * or if an extension runs where the remote extension host runs. The extension kind + * is defined in the `package.json`-file of extensions but can also be refined + * via the `remote.extensionKind`-setting. When no remote extension host exists, + * the value is [`ExtensionKind.UI`](#ExtensionKind.UI). + */ + extensionKind: ExtensionKind; + + /** + * The public API exported by this extension. It is an invalid action + * to access this field before this extension has been activated. + */ + readonly exports: T; + + /** + * Activates this extension and returns its public API. + * + * @return A promise that will resolve when this extension has been activated. + */ + activate(): Thenable; + } + + /** + * The ExtensionMode is provided on the `ExtensionContext` and indicates the + * mode the specific extension is running in. + */ + export enum ExtensionMode { + /** + * The extension is installed normally (for example, from the marketplace + * or VSIX) in VS Code. + */ + Production = 1, + + /** + * The extension is running from an `--extensionDevelopmentPath` provided + * when launching VS Code. + */ + Development = 2, + + /** + * The extension is running from an `--extensionTestsPath` and + * the extension host is running unit tests. + */ + Test = 3, + } + + /** + * An extension context is a collection of utilities private to an + * extension. + * + * An instance of an `ExtensionContext` is provided as the first + * parameter to the `activate`-call of an extension. + */ + export interface ExtensionContext { + + /** + * An array to which disposables can be added. When this + * extension is deactivated the disposables will be disposed. + */ + readonly subscriptions: { dispose(): any }[]; + + /** + * A memento object that stores state in the context + * of the currently opened [workspace](#workspace.workspaceFolders). + */ + readonly workspaceState: Memento; + + /** + * A memento object that stores state independent + * of the current opened [workspace](#workspace.workspaceFolders). + */ + readonly globalState: Memento; + + /** + * The uri of the directory containing the extension. + */ + readonly extensionUri: Uri; + + /** + * The absolute file path of the directory containing the extension. Shorthand + * notation for [ExtensionContext.extensionUri.fsPath](#TextDocument.uri) (independent of the uri scheme). + */ + readonly extensionPath: string; + + /** + * Gets the extension's environment variable collection for this workspace, enabling changes + * to be applied to terminal environment variables. + */ + readonly environmentVariableCollection: EnvironmentVariableCollection; + + /** + * Get the absolute path of a resource contained in the extension. + * + * @param relativePath A relative path to a resource contained in the extension. + * @return The absolute path of the resource. + */ + asAbsolutePath(relativePath: string): string; + + /** + * An absolute file path of a workspace specific directory in which the extension + * can store private state. The directory might not exist on disk and creation is + * up to the extension. However, the parent directory is guaranteed to be existent. + * + * Use [`workspaceState`](#ExtensionContext.workspaceState) or + * [`globalState`](#ExtensionContext.globalState) to store key value data. + */ + readonly storagePath: string | undefined; + + /** + * An absolute file path in which the extension can store global state. + * The directory might not exist on disk and creation is + * up to the extension. However, the parent directory is guaranteed to be existent. + * + * Use [`globalState`](#ExtensionContext.globalState) to store key value data. + */ + readonly globalStoragePath: string; + + /** + * An absolute file path of a directory in which the extension can create log files. + * The directory might not exist on disk and creation is up to the extension. However, + * the parent directory is guaranteed to be existent. + */ + readonly logPath: string; + + /** + * The mode the extension is running in. This is specific to the current + * extension. One extension may be in `ExtensionMode.Development` while + * other extensions in the host run in `ExtensionMode.Release`. + */ + readonly extensionMode: ExtensionMode; + } + + /** + * A memento represents a storage utility. It can store and retrieve + * values. + */ + export interface Memento { + + /** + * Return a value. + * + * @param key A string. + * @return The stored value or `undefined`. + */ + get(key: string): T | undefined; + + /** + * Return a value. + * + * @param key A string. + * @param defaultValue A value that should be returned when there is no + * value (`undefined`) with the given key. + * @return The stored value or the defaultValue. + */ + get(key: string, defaultValue: T): T; + + /** + * Store a value. The value must be JSON-stringifyable. + * + * @param key A string. + * @param value A value. MUST not contain cyclic references. + */ + update(key: string, value: any): Thenable; + } + + /** + * Represents a color theme kind. + */ + export enum ColorThemeKind { + Light = 1, + Dark = 2, + HighContrast = 3 + } + + /** + * Represents a color theme. + */ + export interface ColorTheme { + + /** + * The kind of this color theme: light, dark or high contrast. + */ + readonly kind: ColorThemeKind; + } + + /** + * Controls the behaviour of the terminal's visibility. + */ + export enum TaskRevealKind { + /** + * Always brings the terminal to front if the task is executed. + */ + Always = 1, + + /** + * Only brings the terminal to front if a problem is detected executing the task + * (e.g. the task couldn't be started because). + */ + Silent = 2, + + /** + * The terminal never comes to front when the task is executed. + */ + Never = 3 + } + + /** + * Controls how the task channel is used between tasks + */ + export enum TaskPanelKind { + + /** + * Shares a panel with other tasks. This is the default. + */ + Shared = 1, + + /** + * Uses a dedicated panel for this tasks. The panel is not + * shared with other tasks. + */ + Dedicated = 2, + + /** + * Creates a new panel whenever this task is executed. + */ + New = 3 + } + + /** + * Controls how the task is presented in the UI. + */ + export interface TaskPresentationOptions { + /** + * Controls whether the task output is reveal in the user interface. + * Defaults to `RevealKind.Always`. + */ + reveal?: TaskRevealKind; + + /** + * Controls whether the command associated with the task is echoed + * in the user interface. + */ + echo?: boolean; + + /** + * Controls whether the panel showing the task output is taking focus. + */ + focus?: boolean; + + /** + * Controls if the task panel is used for this task only (dedicated), + * shared between tasks (shared) or if a new panel is created on + * every task execution (new). Defaults to `TaskInstanceKind.Shared` + */ + panel?: TaskPanelKind; + + /** + * Controls whether to show the "Terminal will be reused by tasks, press any key to close it" message. + */ + showReuseMessage?: boolean; + + /** + * Controls whether the terminal is cleared before executing the task. + */ + clear?: boolean; + } + + /** + * A grouping for tasks. The editor by default supports the + * 'Clean', 'Build', 'RebuildAll' and 'Test' group. + */ + export class TaskGroup { + + /** + * The clean task group; + */ + static Clean: TaskGroup; + + /** + * The build task group; + */ + static Build: TaskGroup; + + /** + * The rebuild all task group; + */ + static Rebuild: TaskGroup; + + /** + * The test all task group; + */ + static Test: TaskGroup; + + private constructor(id: string, label: string); + } + + /** + * A structure that defines a task kind in the system. + * The value must be JSON-stringifyable. + */ + export interface TaskDefinition { + /** + * The task definition describing the task provided by an extension. + * Usually a task provider defines more properties to identify + * a task. They need to be defined in the package.json of the + * extension under the 'taskDefinitions' extension point. The npm + * task definition for example looks like this + * ```typescript + * interface NpmTaskDefinition extends TaskDefinition { + * script: string; + * } + * ``` + * + * Note that type identifier starting with a '$' are reserved for internal + * usages and shouldn't be used by extensions. + */ + readonly type: string; + + /** + * Additional attributes of a concrete task definition. + */ + [name: string]: any; + } + + /** + * Options for a process execution + */ + export interface ProcessExecutionOptions { + /** + * The current working directory of the executed program or shell. + * If omitted the tools current workspace root is used. + */ + cwd?: string; + + /** + * The additional environment of the executed program or shell. If omitted + * the parent process' environment is used. If provided it is merged with + * the parent process' environment. + */ + env?: { [key: string]: string }; + } + + /** + * The execution of a task happens as an external process + * without shell interaction. + */ + export class ProcessExecution { + + /** + * Creates a process execution. + * + * @param process The process to start. + * @param options Optional options for the started process. + */ + constructor(process: string, options?: ProcessExecutionOptions); + + /** + * Creates a process execution. + * + * @param process The process to start. + * @param args Arguments to be passed to the process. + * @param options Optional options for the started process. + */ + constructor(process: string, args: string[], options?: ProcessExecutionOptions); + + /** + * The process to be executed. + */ + process: string; + + /** + * The arguments passed to the process. Defaults to an empty array. + */ + args: string[]; + + /** + * The process options used when the process is executed. + * Defaults to undefined. + */ + options?: ProcessExecutionOptions; + } + + /** + * The shell quoting options. + */ + export interface ShellQuotingOptions { + + /** + * The character used to do character escaping. If a string is provided only spaces + * are escaped. If a `{ escapeChar, charsToEscape }` literal is provide all characters + * in `charsToEscape` are escaped using the `escapeChar`. + */ + escape?: string | { + /** + * The escape character. + */ + escapeChar: string; + /** + * The characters to escape. + */ + charsToEscape: string; + }; + + /** + * The character used for strong quoting. The string's length must be 1. + */ + strong?: string; + + /** + * The character used for weak quoting. The string's length must be 1. + */ + weak?: string; + } + + /** + * Options for a shell execution + */ + export interface ShellExecutionOptions { + /** + * The shell executable. + */ + executable?: string; + + /** + * The arguments to be passed to the shell executable used to run the task. Most shells + * require special arguments to execute a command. For example `bash` requires the `-c` + * argument to execute a command, `PowerShell` requires `-Command` and `cmd` requires both + * `/d` and `/c`. + */ + shellArgs?: string[]; + + /** + * The shell quotes supported by this shell. + */ + shellQuoting?: ShellQuotingOptions; + + /** + * The current working directory of the executed shell. + * If omitted the tools current workspace root is used. + */ + cwd?: string; + + /** + * The additional environment of the executed shell. If omitted + * the parent process' environment is used. If provided it is merged with + * the parent process' environment. + */ + env?: { [key: string]: string }; + } + + /** + * Defines how an argument should be quoted if it contains + * spaces or unsupported characters. + */ + export enum ShellQuoting { + + /** + * Character escaping should be used. This for example + * uses \ on bash and ` on PowerShell. + */ + Escape = 1, + + /** + * Strong string quoting should be used. This for example + * uses " for Windows cmd and ' for bash and PowerShell. + * Strong quoting treats arguments as literal strings. + * Under PowerShell echo 'The value is $(2 * 3)' will + * print `The value is $(2 * 3)` + */ + Strong = 2, + + /** + * Weak string quoting should be used. This for example + * uses " for Windows cmd, bash and PowerShell. Weak quoting + * still performs some kind of evaluation inside the quoted + * string. Under PowerShell echo "The value is $(2 * 3)" + * will print `The value is 6` + */ + Weak = 3 + } + + /** + * A string that will be quoted depending on the used shell. + */ + export interface ShellQuotedString { + /** + * The actual string value. + */ + value: string; + + /** + * The quoting style to use. + */ + quoting: ShellQuoting; + } + + export class ShellExecution { + /** + * Creates a shell execution with a full command line. + * + * @param commandLine The command line to execute. + * @param options Optional options for the started the shell. + */ + constructor(commandLine: string, options?: ShellExecutionOptions); + + /** + * Creates a shell execution with a command and arguments. For the real execution VS Code will + * construct a command line from the command and the arguments. This is subject to interpretation + * especially when it comes to quoting. If full control over the command line is needed please + * use the constructor that creates a `ShellExecution` with the full command line. + * + * @param command The command to execute. + * @param args The command arguments. + * @param options Optional options for the started the shell. + */ + constructor(command: string | ShellQuotedString, args: (string | ShellQuotedString)[], options?: ShellExecutionOptions); + + /** + * The shell command line. Is `undefined` if created with a command and arguments. + */ + commandLine: string | undefined; + + /** + * The shell command. Is `undefined` if created with a full command line. + */ + command: string | ShellQuotedString; + + /** + * The shell args. Is `undefined` if created with a full command line. + */ + args: (string | ShellQuotedString)[]; + + /** + * The shell options used when the command line is executed in a shell. + * Defaults to undefined. + */ + options?: ShellExecutionOptions; + } + + /** + * Class used to execute an extension callback as a task. + */ + export class CustomExecution { + /** + * Constructs a CustomExecution task object. The callback will be executed the task is run, at which point the + * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until + * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). + * @param process The [Pseudoterminal](#Pseudoterminal) to be used by the task to display output. + * @param callback The callback that will be called when the task is started by a user. + */ + constructor(callback: () => Thenable); + } + + /** + * The scope of a task. + */ + export enum TaskScope { + /** + * The task is a global task. Global tasks are currently not supported. + */ + Global = 1, + + /** + * The task is a workspace task + */ + Workspace = 2 + } + + /** + * Run options for a task. + */ + export interface RunOptions { + /** + * Controls whether task variables are re-evaluated on rerun. + */ + reevaluateOnRerun?: boolean; + } + + /** + * A task to execute + */ + export class Task { + + /** + * Creates a new task. + * + * @param definition The task definition as defined in the taskDefinitions extension point. + * @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder. Global tasks are currently not supported. + * @param name The task's name. Is presented in the user interface. + * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. + * @param execution The process or shell execution. + * @param problemMatchers the names of problem matchers to use, like '$tsc' + * or '$eslint'. Problem matchers can be contributed by an extension using + * the `problemMatchers` extension point. + */ + constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); + + /** + * ~~Creates a new task.~~ + * + * @deprecated Use the new constructors that allow specifying a scope for the task. + * + * @param definition The task definition as defined in the taskDefinitions extension point. + * @param name The task's name. Is presented in the user interface. + * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. + * @param execution The process or shell execution. + * @param problemMatchers the names of problem matchers to use, like '$tsc' + * or '$eslint'. Problem matchers can be contributed by an extension using + * the `problemMatchers` extension point. + */ + constructor(taskDefinition: TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + + /** + * The task's definition. + */ + definition: TaskDefinition; + + /** + * The task's scope. + */ + readonly scope?: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder; + + /** + * The task's name + */ + name: string; + + /** + * The task's execution engine + */ + execution?: ProcessExecution | ShellExecution | CustomExecution; + + /** + * Whether the task is a background task or not. + */ + isBackground: boolean; + + /** + * A human-readable string describing the source of this shell task, e.g. 'gulp' + * or 'npm'. Supports rendering of [theme icons](#ThemeIcon) via the `$()`-syntax. + */ + source: string; + + /** + * The task group this tasks belongs to. See TaskGroup + * for a predefined set of available groups. + * Defaults to undefined meaning that the task doesn't + * belong to any special group. + */ + group?: TaskGroup; + + /** + * The presentation options. Defaults to an empty literal. + */ + presentationOptions: TaskPresentationOptions; + + /** + * The problem matchers attached to the task. Defaults to an empty + * array. + */ + problemMatchers: string[]; + + /** + * Run options for the task + */ + runOptions: RunOptions; + } + + /** + * A task provider allows to add tasks to the task service. + * A task provider is registered via #tasks.registerTaskProvider. + */ + export interface TaskProvider { + /** + * Provides tasks. + * @param token A cancellation token. + * @return an array of tasks + */ + provideTasks(token?: CancellationToken): ProviderResult; + + /** + * Resolves a task that has no [`execution`](#Task.execution) set. Tasks are + * often created from information found in the `tasks.json`-file. Such tasks miss + * the information on how to execute them and a task provider must fill in + * the missing information in the `resolveTask`-method. This method will not be + * called for tasks returned from the above `provideTasks` method since those + * tasks are always fully resolved. A valid default implementation for the + * `resolveTask` method is to return `undefined`. + * + * @param task The task to resolve. + * @param token A cancellation token. + * @return The resolved task + */ + resolveTask(task: T, token?: CancellationToken): ProviderResult; + } + + /** + * An object representing an executed Task. It can be used + * to terminate a task. + * + * This interface is not intended to be implemented. + */ + export interface TaskExecution { + /** + * The task that got started. + */ + task: Task; + + /** + * Terminates the task execution. + */ + terminate(): void; + } + + /** + * An event signaling the start of a task execution. + * + * This interface is not intended to be implemented. + */ + interface TaskStartEvent { + /** + * The task item representing the task that got started. + */ + readonly execution: TaskExecution; + } + + /** + * An event signaling the end of an executed task. + * + * This interface is not intended to be implemented. + */ + interface TaskEndEvent { + /** + * The task item representing the task that finished. + */ + readonly execution: TaskExecution; + } + + /** + * An event signaling the start of a process execution + * triggered through a task + */ + export interface TaskProcessStartEvent { + + /** + * The task execution for which the process got started. + */ + readonly execution: TaskExecution; + + /** + * The underlying process id. + */ + readonly processId: number; + } + + /** + * An event signaling the end of a process execution + * triggered through a task + */ + export interface TaskProcessEndEvent { + + /** + * The task execution for which the process got started. + */ + readonly execution: TaskExecution; + + /** + * The process's exit code. + */ + readonly exitCode: number; + } + + export interface TaskFilter { + /** + * The task version as used in the tasks.json file. + * The string support the package.json semver notation. + */ + version?: string; + + /** + * The task type to return; + */ + type?: string; + } + + /** + * Namespace for tasks functionality. + */ + export namespace tasks { + + /** + * Register a task provider. + * + * @param type The task kind type this provider is registered for. + * @param provider A task provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTaskProvider(type: string, provider: TaskProvider): Disposable; + + /** + * Fetches all tasks available in the systems. This includes tasks + * from `tasks.json` files as well as tasks from task providers + * contributed through extensions. + * + * @param filter Optional filter to select tasks of a certain type or version. + */ + export function fetchTasks(filter?: TaskFilter): Thenable; + + /** + * Executes a task that is managed by VS Code. The returned + * task execution can be used to terminate the task. + * + * @throws When running a ShellExecution or a ProcessExecution + * task in an environment where a new process cannot be started. + * In such an environment, only CustomExecution tasks can be run. + * + * @param task the task to execute + */ + export function executeTask(task: Task): Thenable; + + /** + * The currently active task executions or an empty array. + */ + export const taskExecutions: ReadonlyArray; + + /** + * Fires when a task starts. + */ + export const onDidStartTask: Event; + + /** + * Fires when a task ends. + */ + export const onDidEndTask: Event; + + /** + * Fires when the underlying process has been started. + * This event will not fire for tasks that don't + * execute an underlying process. + */ + export const onDidStartTaskProcess: Event; + + /** + * Fires when the underlying process has ended. + * This event will not fire for tasks that don't + * execute an underlying process. + */ + export const onDidEndTaskProcess: Event; + } + + /** + * Enumeration of file types. The types `File` and `Directory` can also be + * a symbolic links, in that case use `FileType.File | FileType.SymbolicLink` and + * `FileType.Directory | FileType.SymbolicLink`. + */ + export enum FileType { + /** + * The file type is unknown. + */ + Unknown = 0, + /** + * A regular file. + */ + File = 1, + /** + * A directory. + */ + Directory = 2, + /** + * A symbolic link to a file. + */ + SymbolicLink = 64 + } + + /** + * The `FileStat`-type represents metadata about a file + */ + export interface FileStat { + /** + * The type of the file, e.g. is a regular file, a directory, or symbolic link + * to a file. + * + * *Note:* This value might be a bitmask, e.g. `FileType.File | FileType.SymbolicLink`. + */ + type: FileType; + /** + * The creation timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC. + */ + ctime: number; + /** + * The modification timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC. + * + * *Note:* If the file changed, it is important to provide an updated `mtime` that advanced + * from the previous value. Otherwise there may be optimizations in place that will not show + * the updated file contents in an editor for example. + */ + mtime: number; + /** + * The size in bytes. + * + * *Note:* If the file changed, it is important to provide an updated `size`. Otherwise there + * may be optimizations in place that will not show the updated file contents in an editor for + * example. + */ + size: number; + } + + /** + * A type that filesystem providers should use to signal errors. + * + * This class has factory methods for common error-cases, like `FileNotFound` when + * a file or folder doesn't exist, use them like so: `throw vscode.FileSystemError.FileNotFound(someUri);` + */ + export class FileSystemError extends Error { + + /** + * Create an error to signal that a file or folder wasn't found. + * @param messageOrUri Message or uri. + */ + static FileNotFound(messageOrUri?: string | Uri): FileSystemError; + + /** + * Create an error to signal that a file or folder already exists, e.g. when + * creating but not overwriting a file. + * @param messageOrUri Message or uri. + */ + static FileExists(messageOrUri?: string | Uri): FileSystemError; + + /** + * Create an error to signal that a file is not a folder. + * @param messageOrUri Message or uri. + */ + static FileNotADirectory(messageOrUri?: string | Uri): FileSystemError; + + /** + * Create an error to signal that a file is a folder. + * @param messageOrUri Message or uri. + */ + static FileIsADirectory(messageOrUri?: string | Uri): FileSystemError; + + /** + * Create an error to signal that an operation lacks required permissions. + * @param messageOrUri Message or uri. + */ + static NoPermissions(messageOrUri?: string | Uri): FileSystemError; + + /** + * Create an error to signal that the file system is unavailable or too busy to + * complete a request. + * @param messageOrUri Message or uri. + */ + static Unavailable(messageOrUri?: string | Uri): FileSystemError; + + /** + * Creates a new filesystem error. + * + * @param messageOrUri Message or uri. + */ + constructor(messageOrUri?: string | Uri); + + /** + * A code that identifies this error. + * + * Possible values are names of errors, like [`FileNotFound`](#FileSystemError.FileNotFound), + * or `Unknown` for unspecified errors. + */ + readonly code: string; + } + + /** + * Enumeration of file change types. + */ + export enum FileChangeType { + + /** + * The contents or metadata of a file have changed. + */ + Changed = 1, + + /** + * A file has been created. + */ + Created = 2, + + /** + * A file has been deleted. + */ + Deleted = 3, + } + + /** + * The event filesystem providers must use to signal a file change. + */ + export interface FileChangeEvent { + + /** + * The type of change. + */ + readonly type: FileChangeType; + + /** + * The uri of the file that has changed. + */ + readonly uri: Uri; + } + + /** + * The filesystem provider defines what the editor needs to read, write, discover, + * and to manage files and folders. It allows extensions to serve files from remote places, + * like ftp-servers, and to seamlessly integrate those into the editor. + * + * * *Note 1:* The filesystem provider API works with [uris](#Uri) and assumes hierarchical + * paths, e.g. `foo:/my/path` is a child of `foo:/my/` and a parent of `foo:/my/path/deeper`. + * * *Note 2:* There is an activation event `onFileSystem:` that fires when a file + * or folder is being accessed. + * * *Note 3:* The word 'file' is often used to denote all [kinds](#FileType) of files, e.g. + * folders, symbolic links, and regular files. + */ + export interface FileSystemProvider { + + /** + * An event to signal that a resource has been created, changed, or deleted. This + * event should fire for resources that are being [watched](#FileSystemProvider.watch) + * by clients of this provider. + * + * *Note:* It is important that the metadata of the file that changed provides an + * updated `mtime` that advanced from the previous value in the [stat](#FileStat) and a + * correct `size` value. Otherwise there may be optimizations in place that will not show + * the change in an editor for example. + */ + readonly onDidChangeFile: Event; + + /** + * Subscribe to events in the file or folder denoted by `uri`. + * + * The editor will call this function for files and folders. In the latter case, the + * options differ from defaults, e.g. what files/folders to exclude from watching + * and if subfolders, sub-subfolder, etc. should be watched (`recursive`). + * + * @param uri The uri of the file to be watched. + * @param options Configures the watch. + * @returns A disposable that tells the provider to stop watching the `uri`. + */ + watch(uri: Uri, options: { recursive: boolean; excludes: string[] }): Disposable; + + /** + * Retrieve metadata about a file. + * + * Note that the metadata for symbolic links should be the metadata of the file they refer to. + * Still, the [SymbolicLink](#FileType.SymbolicLink)-type must be used in addition to the actual type, e.g. + * `FileType.SymbolicLink | FileType.Directory`. + * + * @param uri The uri of the file to retrieve metadata about. + * @return The file metadata about the file. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + */ + stat(uri: Uri): FileStat | Thenable; + + /** + * Retrieve all entries of a [directory](#FileType.Directory). + * + * @param uri The uri of the folder. + * @return An array of name/type-tuples or a thenable that resolves to such. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + */ + readDirectory(uri: Uri): [string, FileType][] | Thenable<[string, FileType][]>; + + /** + * Create a new directory (Note, that new files are created via `write`-calls). + * + * @param uri The uri of the new folder. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when the parent of `uri` doesn't exist, e.g. no mkdirp-logic required. + * @throws [`FileExists`](#FileSystemError.FileExists) when `uri` already exists. + * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + */ + createDirectory(uri: Uri): void | Thenable; + + /** + * Read the entire contents of a file. + * + * @param uri The uri of the file. + * @return An array of bytes or a thenable that resolves to such. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + */ + readFile(uri: Uri): Uint8Array | Thenable; + + /** + * Write data to a file, replacing its entire contents. + * + * @param uri The uri of the file. + * @param content The new content of the file. + * @param options Defines if missing files should or must be created. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist and `create` is not set. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when the parent of `uri` doesn't exist and `create` is set, e.g. no mkdirp-logic required. + * @throws [`FileExists`](#FileSystemError.FileExists) when `uri` already exists, `create` is set but `overwrite` is not set. + * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + */ + writeFile(uri: Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void | Thenable; + + /** + * Delete a file. + * + * @param uri The resource that is to be deleted. + * @param options Defines if deletion of folders is recursive. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + */ + delete(uri: Uri, options: { recursive: boolean }): void | Thenable; + + /** + * Rename a file or folder. + * + * @param oldUri The existing file. + * @param newUri The new location. + * @param options Defines if existing files should be overwritten. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `oldUri` doesn't exist. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when parent of `newUri` doesn't exist, e.g. no mkdirp-logic required. + * @throws [`FileExists`](#FileSystemError.FileExists) when `newUri` exists and when the `overwrite` option is not `true`. + * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + */ + rename(oldUri: Uri, newUri: Uri, options: { overwrite: boolean }): void | Thenable; + + /** + * Copy files or folders. Implementing this function is optional but it will speedup + * the copy operation. + * + * @param source The existing file. + * @param destination The destination location. + * @param options Defines if existing files should be overwritten. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `source` doesn't exist. + * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when parent of `destination` doesn't exist, e.g. no mkdirp-logic required. + * @throws [`FileExists`](#FileSystemError.FileExists) when `destination` exists and when the `overwrite` option is not `true`. + * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + */ + copy?(source: Uri, destination: Uri, options: { overwrite: boolean }): void | Thenable; + } + + /** + * The file system interface exposes the editor's built-in and contributed + * [file system providers](#FileSystemProvider). It allows extensions to work + * with files from the local disk as well as files from remote places, like the + * remote extension host or ftp-servers. + * + * *Note* that an instance of this interface is available as [`workspace.fs`](#workspace.fs). + */ + export interface FileSystem { + + /** + * Retrieve metadata about a file. + * + * @param uri The uri of the file to retrieve metadata about. + * @return The file metadata about the file. + */ + stat(uri: Uri): Thenable; + + /** + * Retrieve all entries of a [directory](#FileType.Directory). + * + * @param uri The uri of the folder. + * @return An array of name/type-tuples or a thenable that resolves to such. + */ + readDirectory(uri: Uri): Thenable<[string, FileType][]>; + + /** + * Create a new directory (Note, that new files are created via `write`-calls). + * + * *Note* that missing directories are created automatically, e.g this call has + * `mkdirp` semantics. + * + * @param uri The uri of the new folder. + */ + createDirectory(uri: Uri): Thenable; + + /** + * Read the entire contents of a file. + * + * @param uri The uri of the file. + * @return An array of bytes or a thenable that resolves to such. + */ + readFile(uri: Uri): Thenable; + + /** + * Write data to a file, replacing its entire contents. + * + * @param uri The uri of the file. + * @param content The new content of the file. + */ + writeFile(uri: Uri, content: Uint8Array): Thenable; + + /** + * Delete a file. + * + * @param uri The resource that is to be deleted. + * @param options Defines if trash can should be used and if deletion of folders is recursive + */ + delete(uri: Uri, options?: { recursive?: boolean, useTrash?: boolean }): Thenable; + + /** + * Rename a file or folder. + * + * @param oldUri The existing file. + * @param newUri The new location. + * @param options Defines if existing files should be overwritten. + */ + rename(source: Uri, target: Uri, options?: { overwrite?: boolean }): Thenable; + + /** + * Copy files or folders. + * + * @param source The existing file. + * @param destination The destination location. + * @param options Defines if existing files should be overwritten. + */ + copy(source: Uri, target: Uri, options?: { overwrite?: boolean }): Thenable; + } + + /** + * Defines a port mapping used for localhost inside the webview. + */ + export interface WebviewPortMapping { + /** + * Localhost port to remap inside the webview. + */ + readonly webviewPort: number; + + /** + * Destination port. The `webviewPort` is resolved to this port. + */ + readonly extensionHostPort: number; + } + + /** + * Content settings for a webview. + */ + export interface WebviewOptions { + /** + * Controls whether scripts are enabled in the webview content or not. + * + * Defaults to false (scripts-disabled). + */ + readonly enableScripts?: boolean; + + /** + * Controls whether command uris are enabled in webview content or not. + * + * Defaults to false. + */ + readonly enableCommandUris?: boolean; + + /** + * Root paths from which the webview can load local (filesystem) resources using uris from `asWebviewUri` + * + * Default to the root folders of the current workspace plus the extension's install directory. + * + * Pass in an empty array to disallow access to any local resources. + */ + readonly localResourceRoots?: ReadonlyArray; + + /** + * Mappings of localhost ports used inside the webview. + * + * Port mapping allow webviews to transparently define how localhost ports are resolved. This can be used + * to allow using a static localhost port inside the webview that is resolved to random port that a service is + * running on. + * + * If a webview accesses localhost content, we recommend that you specify port mappings even if + * the `webviewPort` and `extensionHostPort` ports are the same. + * + * *Note* that port mappings only work for `http` or `https` urls. Websocket urls (e.g. `ws://localhost:3000`) + * cannot be mapped to another port. + */ + readonly portMapping?: ReadonlyArray; + } + + /** + * Displays html content, similarly to an iframe. + */ + export interface Webview { + /** + * Content settings for the webview. + */ + options: WebviewOptions; + + /** + * HTML contents of the webview. + * + * This should be a complete, valid html document. Changing this property causes the webview to be reloaded. + * + * Webviews are sandboxed from normal extension process, so all communication with the webview must use + * message passing. To send a message from the extension to the webview, use [`postMessage`](#Webview.postMessage). + * To send message from the webview back to an extension, use the `acquireVsCodeApi` function inside the webview + * to get a handle to VS Code's api and then call `.postMessage()`: + * + * ```html + * + * ``` + * + * To load a resources from the workspace inside a webview, use the `[asWebviewUri](#Webview.asWebviewUri)` method + * and ensure the resource's directory is listed in [`WebviewOptions.localResourceRoots`](#WebviewOptions.localResourceRoots). + * + * Keep in mind that even though webviews are sandboxed, they still allow running scripts and loading arbitrary content, + * so extensions must follow all standard web security best practices when working with webviews. This includes + * properly sanitizing all untrusted input (including content from the workspace) and + * setting a [content security policy](https://aka.ms/vscode-api-webview-csp). + */ + html: string; + + /** + * Fired when the webview content posts a message. + * + * Webview content can post strings or json serilizable objects back to a VS Code extension. They cannot + * post `Blob`, `File`, `ImageData` and other DOM specific objects since the extension that receives the + * message does not run in a browser environment. + */ + readonly onDidReceiveMessage: Event; + + /** + * Post a message to the webview content. + * + * Messages are only delivered if the webview is live (either visible or in the + * background with `retainContextWhenHidden`). + * + * @param message Body of the message. This must be a string or other json serilizable object. + */ + postMessage(message: any): Thenable; + + /** + * Convert a uri for the local file system to one that can be used inside webviews. + * + * Webviews cannot directly load resources from the workspace or local file system using `file:` uris. The + * `asWebviewUri` function takes a local `file:` uri and converts it into a uri that can be used inside of + * a webview to load the same resource: + * + * ```ts + * webview.html = `` + * ``` + */ + asWebviewUri(localResource: Uri): Uri; + + /** + * Content security policy source for webview resources. + * + * This is the origin that should be used in a content security policy rule: + * + * ``` + * img-src https: ${webview.cspSource} ...; + * ``` + */ + readonly cspSource: string; + } + + /** + * Content settings for a webview panel. + */ + export interface WebviewPanelOptions { + /** + * Controls if the find widget is enabled in the panel. + * + * Defaults to false. + */ + readonly enableFindWidget?: boolean; + + /** + * Controls if the webview panel's content (iframe) is kept around even when the panel + * is no longer visible. + * + * Normally the webview panel's html context is created when the panel becomes visible + * and destroyed when it is hidden. Extensions that have complex state + * or UI can set the `retainContextWhenHidden` to make VS Code keep the webview + * context around, even when the webview moves to a background tab. When a webview using + * `retainContextWhenHidden` becomes hidden, its scripts and other dynamic content are suspended. + * When the panel becomes visible again, the context is automatically restored + * in the exact same state it was in originally. You cannot send messages to a + * hidden webview, even with `retainContextWhenHidden` enabled. + * + * `retainContextWhenHidden` has a high memory overhead and should only be used if + * your panel's context cannot be quickly saved and restored. + */ + readonly retainContextWhenHidden?: boolean; + } + + /** + * A panel that contains a webview. + */ + interface WebviewPanel { + /** + * Identifies the type of the webview panel, such as `'markdown.preview'`. + */ + readonly viewType: string; + + /** + * Title of the panel shown in UI. + */ + title: string; + + /** + * Icon for the panel shown in UI. + */ + iconPath?: Uri | { light: Uri; dark: Uri }; + + /** + * [`Webview`](#Webview) belonging to the panel. + */ + readonly webview: Webview; + + /** + * Content settings for the webview panel. + */ + readonly options: WebviewPanelOptions; + + /** + * Editor position of the panel. This property is only set if the webview is in + * one of the editor view columns. + */ + readonly viewColumn?: ViewColumn; + + /** + * Whether the panel is active (focused by the user). + */ + readonly active: boolean; + + /** + * Whether the panel is visible. + */ + readonly visible: boolean; + + /** + * Fired when the panel's view state changes. + */ + readonly onDidChangeViewState: Event; + + /** + * Fired when the panel is disposed. + * + * This may be because the user closed the panel or because `.dispose()` was + * called on it. + * + * Trying to use the panel after it has been disposed throws an exception. + */ + readonly onDidDispose: Event; + + /** + * Show the webview panel in a given column. + * + * A webview panel may only show in a single column at a time. If it is already showing, this + * method moves it to a new column. + * + * @param viewColumn View column to show the panel in. Shows in the current `viewColumn` if undefined. + * @param preserveFocus When `true`, the webview will not take focus. + */ + reveal(viewColumn?: ViewColumn, preserveFocus?: boolean): void; + + /** + * Dispose of the webview panel. + * + * This closes the panel if it showing and disposes of the resources owned by the webview. + * Webview panels are also disposed when the user closes the webview panel. Both cases + * fire the `onDispose` event. + */ + dispose(): any; + } + + /** + * Event fired when a webview panel's view state changes. + */ + export interface WebviewPanelOnDidChangeViewStateEvent { + /** + * Webview panel whose view state changed. + */ + readonly webviewPanel: WebviewPanel; + } + + /** + * Restore webview panels that have been persisted when vscode shuts down. + * + * There are two types of webview persistence: + * + * - Persistence within a session. + * - Persistence across sessions (across restarts of VS Code). + * + * A `WebviewPanelSerializer` is only required for the second case: persisting a webview across sessions. + * + * Persistence within a session allows a webview to save its state when it becomes hidden + * and restore its content from this state when it becomes visible again. It is powered entirely + * by the webview content itself. To save off a persisted state, call `acquireVsCodeApi().setState()` with + * any json serializable object. To restore the state again, call `getState()` + * + * ```js + * // Within the webview + * const vscode = acquireVsCodeApi(); + * + * // Get existing state + * const oldState = vscode.getState() || { value: 0 }; + * + * // Update state + * setState({ value: oldState.value + 1 }) + * ``` + * + * A `WebviewPanelSerializer` extends this persistence across restarts of VS Code. When the editor is shutdown, + * VS Code will save off the state from `setState` of all webviews that have a serializer. When the + * webview first becomes visible after the restart, this state is passed to `deserializeWebviewPanel`. + * The extension can then restore the old `WebviewPanel` from this state. + */ + interface WebviewPanelSerializer { + /** + * Restore a webview panel from its serialized `state`. + * + * Called when a serialized webview first becomes visible. + * + * @param webviewPanel Webview panel to restore. The serializer should take ownership of this panel. The + * serializer must restore the webview's `.html` and hook up all webview events. + * @param state Persisted state from the webview content. + * + * @return Thenable indicating that the webview has been fully restored. + */ + deserializeWebviewPanel(webviewPanel: WebviewPanel, state: any): Thenable; + } + + /** + * Provider for text based custom editors. + * + * Text based custom editors use a [`TextDocument`](#TextDocument) as their data model. This considerably simplifies + * implementing a custom editor as it allows VS Code to handle many common operations such as + * undo and backup. The provider is responsible for synchronizing text changes between the webview and the `TextDocument`. + */ + export interface CustomTextEditorProvider { + + /** + * Resolve a custom editor for a given text resource. + * + * This is called when a user first opens a resource for a `CustomTextEditorProvider`, or if they reopen an + * existing editor using this `CustomTextEditorProvider`. + * + * + * @param document Document for the resource to resolve. + * + * @param webviewPanel The webview panel used to display the editor UI for this resource. + * + * During resolve, the provider must fill in the initial html for the content webview panel and hook up all + * the event listeners on it that it is interested in. The provider can also hold onto the `WebviewPanel` to + * use later for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details. + * + * @param token A cancellation token that indicates the result is no longer needed. + * + * @return Thenable indicating that the custom editor has been resolved. + */ + resolveCustomTextEditor(document: TextDocument, webviewPanel: WebviewPanel, token: CancellationToken): Thenable | void; + } + + /** + * Represents a custom document used by a [`CustomEditorProvider`](#CustomEditorProvider). + * + * Custom documents are only used within a given `CustomEditorProvider`. The lifecycle of a `CustomDocument` is + * managed by VS Code. When no more references remain to a `CustomDocument`, it is disposed of. + */ + interface CustomDocument { + /** + * The associated uri for this document. + */ + readonly uri: Uri; + + /** + * Dispose of the custom document. + * + * This is invoked by VS Code when there are no more references to a given `CustomDocument` (for example when + * all editors associated with the document have been closed.) + */ + dispose(): void; + } + + /** + * Event triggered by extensions to signal to VS Code that an edit has occurred on an [`CustomDocument`](#CustomDocument). + * + * @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument). + */ + interface CustomDocumentEditEvent { + + /** + * The document that the edit is for. + */ + readonly document: T; + + /** + * Undo the edit operation. + * + * This is invoked by VS Code when the user undoes this edit. To implement `undo`, your + * extension should restore the document and editor to the state they were in just before this + * edit was added to VS Code's internal edit stack by `onDidChangeCustomDocument`. + */ + undo(): Thenable | void; + + /** + * Redo the edit operation. + * + * This is invoked by VS Code when the user redoes this edit. To implement `redo`, your + * extension should restore the document and editor to the state they were in just after this + * edit was added to VS Code's internal edit stack by `onDidChangeCustomDocument`. + */ + redo(): Thenable | void; + + /** + * Display name describing the edit. + * + * This will be shown to users in the UI for undo/redo operations. + */ + readonly label?: string; + } + + /** + * Event triggered by extensions to signal to VS Code that the content of a [`CustomDocument`](#CustomDocument) + * has changed. + * + * @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument). + */ + interface CustomDocumentContentChangeEvent { + /** + * The document that the change is for. + */ + readonly document: T; + } + + /** + * A backup for an [`CustomDocument`](#CustomDocument). + */ + interface CustomDocumentBackup { + /** + * Unique identifier for the backup. + * + * This id is passed back to your extension in `openCustomDocument` when opening a custom editor from a backup. + */ + readonly id: string; + + /** + * Delete the current backup. + * + * This is called by VS Code when it is clear the current backup is no longer needed, such as when a new backup + * is made or when the file is saved. + */ + delete(): void; + } + + /** + * Additional information used to implement [`CustomEditableDocument.backup`](#CustomEditableDocument.backup). + */ + interface CustomDocumentBackupContext { + /** + * Suggested file location to write the new backup. + * + * Note that your extension is free to ignore this and use its own strategy for backup. + * + * If the editor is for a resource from the current workspace, `destination` will point to a file inside + * `ExtensionContext.storagePath`. The parent folder of `destination` may not exist, so make sure to created it + * before writing the backup to this location. + */ + readonly destination: Uri; + } + + /** + * Additional information about the opening custom document. + */ + interface CustomDocumentOpenContext { + /** + * The id of the backup to restore the document from or `undefined` if there is no backup. + * + * If this is provided, your extension should restore the editor from the backup instead of reading the file + * from the user's workspace. + */ + readonly backupId?: string; + } + + /** + * Provider for readonly custom editors that use a custom document model. + * + * Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument). + * + * You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple + * text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead. + * + * @param T Type of the custom document returned by this provider. + */ + export interface CustomReadonlyEditorProvider { + + /** + * Create a new document for a given resource. + * + * `openCustomDocument` is called when the first time an editor for a given resource is opened. The opened + * document is then passed to `resolveCustomEditor` so that the editor can be shown to the user. + * + * Already opened `CustomDocument` are re-used if the user opened additional editors. When all editors for a + * given resource are closed, the `CustomDocument` is disposed of. Opening an editor at this point will + * trigger another call to `openCustomDocument`. + * + * @param uri Uri of the document to open. + * @param openContext Additional information about the opening custom document. + * @param token A cancellation token that indicates the result is no longer needed. + * + * @return The custom document. + */ + openCustomDocument(uri: Uri, openContext: CustomDocumentOpenContext, token: CancellationToken): Thenable | T; + + /** + * Resolve a custom editor for a given resource. + * + * This is called whenever the user opens a new editor for this `CustomEditorProvider`. + * + * @param document Document for the resource being resolved. + * + * @param webviewPanel The webview panel used to display the editor UI for this resource. + * + * During resolve, the provider must fill in the initial html for the content webview panel and hook up all + * the event listeners on it that it is interested in. The provider can also hold onto the `WebviewPanel` to + * use later for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details. + * + * @param token A cancellation token that indicates the result is no longer needed. + * + * @return Optional thenable indicating that the custom editor has been resolved. + */ + resolveCustomEditor(document: T, webviewPanel: WebviewPanel, token: CancellationToken): Thenable | void; + } + + /** + * Provider for editable custom editors that use a custom document model. + * + * Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument). + * This gives extensions full control over actions such as edit, save, and backup. + * + * You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple + * text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead. + * + * @param T Type of the custom document returned by this provider. + */ + export interface CustomEditorProvider extends CustomReadonlyEditorProvider { + /** + * Signal that an edit has occurred inside a custom editor. + * + * This event must be fired by your extension whenever an edit happens in a custom editor. An edit can be + * anything from changing some text, to cropping an image, to reordering a list. Your extension is free to + * define what an edit is and what data is stored on each edit. + * + * Firing `onDidChange` causes VS Code to mark the editors as being dirty. This is cleared when the user either + * saves or reverts the file. + * + * Editors that support undo/redo must fire a `CustomDocumentEditEvent` whenever an edit happens. This allows + * users to undo and redo the edit using VS Code's standard VS Code keyboard shortcuts. VS Code will also mark + * the editor as no longer being dirty if the user undoes all edits to the last saved state. + * + * Editors that support editing but cannot use VS Code's standard undo/redo mechanism must fire a `CustomDocumentContentChangeEvent`. + * The only way for a user to clear the dirty state of an editor that does not support undo/redo is to either + * `save` or `revert` the file. + * + * An editor should only ever fire `CustomDocumentEditEvent` events, or only ever fire `CustomDocumentContentChangeEvent` events. + */ + readonly onDidChangeCustomDocument: Event> | Event>; + + /** + * Save a custom document. + * + * This method is invoked by VS Code when the user saves a custom editor. This can happen when the user + * triggers save while the custom editor is active, by commands such as `save all`, or by auto save if enabled. + * + * To implement `save`, the implementer must persist the custom editor. This usually means writing the + * file data for the custom document to disk. After `save` completes, any associated editor instances will + * no longer be marked as dirty. + * + * @param document Document to save. + * @param cancellation Token that signals the save is no longer required (for example, if another save was triggered). + * + * @return Thenable signaling that saving has completed. + */ + saveCustomDocument(document: T, cancellation: CancellationToken): Thenable; + + /** + * Save a custom document to a different location. + * + * This method is invoked by VS Code when the user triggers 'save as' on a custom editor. The implementer must + * persist the custom editor to `destination`. + * + * When the user accepts save as, the current editor is be replaced by an non-dirty editor for the newly saved file. + * + * @param document Document to save. + * @param destination Location to save to. + * @param cancellation Token that signals the save is no longer required. + * + * @return Thenable signaling that saving has completed. + */ + saveCustomDocumentAs(document: T, destination: Uri, cancellation: CancellationToken): Thenable; + + /** + * Revert a custom document to its last saved state. + * + * This method is invoked by VS Code when the user triggers `File: Revert File` in a custom editor. (Note that + * this is only used using VS Code's `File: Revert File` command and not on a `git revert` of the file). + * + * To implement `revert`, the implementer must make sure all editor instances (webviews) for `document` + * are displaying the document in the same state is saved in. This usually means reloading the file from the + * workspace. + * + * @param document Document to revert. + * @param cancellation Token that signals the revert is no longer required. + * + * @return Thenable signaling that the change has completed. + */ + revertCustomDocument(document: T, cancellation: CancellationToken): Thenable; + + /** + * Back up a dirty custom document. + * + * Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in + * its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in + * the `ExtensionContext.storagePath`. When VS Code reloads and your custom editor is opened for a resource, + * your extension should first check to see if any backups exist for the resource. If there is a backup, your + * extension should load the file contents from there instead of from the resource in the workspace. + * + * `backup` is triggered approximately one second after the the user stops editing the document. If the user + * rapidly edits the document, `backup` will not be invoked until the editing stops. + * + * `backup` is not invoked when `auto save` is enabled (since auto save already persists the resource). + * + * @param document Document to backup. + * @param context Information that can be used to backup the document. + * @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your + * extension to decided how to respond to cancellation. If for example your extension is backing up a large file + * in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather + * than cancelling it to ensure that VS Code has some valid backup. + */ + backupCustomDocument(document: T, context: CustomDocumentBackupContext, cancellation: CancellationToken): Thenable; + } + + /** + * The clipboard provides read and write access to the system's clipboard. + */ + export interface Clipboard { + + /** + * Read the current clipboard contents as text. + * @returns A thenable that resolves to a string. + */ + readText(): Thenable; + + /** + * Writes text into the clipboard. + * @returns A thenable that resolves when writing happened. + */ + writeText(value: string): Thenable; + } + + /** + * Possible kinds of UI that can use extensions. + */ + export enum UIKind { + + /** + * Extensions are accessed from a desktop application. + */ + Desktop = 1, + + /** + * Extensions are accessed from a web browser. + */ + Web = 2 + } + + /** + * Namespace describing the environment the editor runs in. + */ + export namespace env { + + /** + * The application name of the editor, like 'VS Code'. + */ + export const appName: string; + + /** + * The application root folder from which the editor is running. + * + * *Note* that the value is the empty string when running in an + * environment that has no representation of an application root folder. + */ + export const appRoot: string; + + /** + * The custom uri scheme the editor registers to in the operating system. + */ + export const uriScheme: string; + + /** + * Represents the preferred user-language, like `de-CH`, `fr`, or `en-US`. + */ + export const language: string; + + /** + * The system clipboard. + */ + export const clipboard: Clipboard; + + /** + * A unique identifier for the computer. + */ + export const machineId: string; + + /** + * A unique identifier for the current session. + * Changes each time the editor is started. + */ + export const sessionId: string; + + /** + * The name of a remote. Defined by extensions, popular samples are `wsl` for the Windows + * Subsystem for Linux or `ssh-remote` for remotes using a secure shell. + * + * *Note* that the value is `undefined` when there is no remote extension host but that the + * value is defined in all extension hosts (local and remote) in case a remote extension host + * exists. Use [`Extension#extensionKind`](#Extension.extensionKind) to know if + * a specific extension runs remote or not. + */ + export const remoteName: string | undefined; + + /** + * The detected default shell for the extension host, this is overridden by the + * `terminal.integrated.shell` setting for the extension host's platform. Note that in + * environments that do not support a shell the value is the empty string. + */ + export const shell: string; + + /** + * The UI kind property indicates from which UI extensions + * are accessed from. For example, extensions could be accessed + * from a desktop application or a web browser. + */ + export const uiKind: UIKind; + + /** + * Opens a link externally using the default application. Depending on the + * used scheme this can be: + * * a browser (`http:`, `https:`) + * * a mail client (`mailto:`) + * * VSCode itself (`vscode:` from `vscode.env.uriScheme`) + * + * *Note* that [`showTextDocument`](#window.showTextDocument) is the right + * way to open a text document inside the editor, not this function. + * + * @param target The uri that should be opened. + * @returns A promise indicating if open was successful. + */ + export function openExternal(target: Uri): Thenable; + + /** + * Resolves a uri to form that is accessible externally. Currently only supports `https:`, `http:` and + * `vscode.env.uriScheme` uris. + * + * #### `http:` or `https:` scheme + * + * Resolves an *external* uri, such as a `http:` or `https:` link, from where the extension is running to a + * uri to the same resource on the client machine. + * + * This is a no-op if the extension is running on the client machine. + * + * If the extension is running remotely, this function automatically establishes a port forwarding tunnel + * from the local machine to `target` on the remote and returns a local uri to the tunnel. The lifetime of + * the port forwarding tunnel is managed by VS Code and the tunnel can be closed by the user. + * + * *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` on them. + * + * #### `vscode.env.uriScheme` + * + * Creates a uri that - if opened in a browser (e.g. via `openExternal`) - will result in a registered [UriHandler](#UriHandler) + * to trigger. + * + * Extensions should not make any assumptions about the resulting uri and should not alter it in anyway. + * Rather, extensions can e.g. use this uri in an authentication flow, by adding the uri as callback query + * argument to the server to authenticate to. + * + * *Note* that if the server decides to add additional query parameters to the uri (e.g. a token or secret), it + * will appear in the uri that is passed to the [UriHandler](#UriHandler). + * + * **Example** of an authentication flow: + * ```typescript + * vscode.window.registerUriHandler({ + * handleUri(uri: vscode.Uri): vscode.ProviderResult { + * if (uri.path === '/did-authenticate') { + * console.log(uri.toString()); + * } + * } + * }); + * + * const callableUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://my.extension/did-authenticate`)); + * await vscode.env.openExternal(callableUri); + * ``` + * + * *Note* that extensions should not cache the result of `asExternalUri` as the resolved uri may become invalid due to + * a system or user action — for example, in remote cases, a user may close a port forwarding tunnel that was opened by + * `asExternalUri`. + * + * @return A uri that can be used on the client machine. + */ + export function asExternalUri(target: Uri): Thenable; + } + + /** + * Namespace for dealing with commands. In short, a command is a function with a + * unique identifier. The function is sometimes also called _command handler_. + * + * Commands can be added to the editor using the [registerCommand](#commands.registerCommand) + * and [registerTextEditorCommand](#commands.registerTextEditorCommand) functions. Commands + * can be executed [manually](#commands.executeCommand) or from a UI gesture. Those are: + * + * * palette - Use the `commands`-section in `package.json` to make a command show in + * the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette). + * * keybinding - Use the `keybindings`-section in `package.json` to enable + * [keybindings](https://code.visualstudio.com/docs/getstarted/keybindings#_customizing-shortcuts) + * for your extension. + * + * Commands from other extensions and from the editor itself are accessible to an extension. However, + * when invoking an editor command not all argument types are supported. + * + * This is a sample that registers a command handler and adds an entry for that command to the palette. First + * register a command handler with the identifier `extension.sayHello`. + * ```javascript + * commands.registerCommand('extension.sayHello', () => { + * window.showInformationMessage('Hello World!'); + * }); + * ``` + * Second, bind the command identifier to a title under which it will show in the palette (`package.json`). + * ```json + * { + * "contributes": { + * "commands": [{ + * "command": "extension.sayHello", + * "title": "Hello World" + * }] + * } + * } + * ``` + */ + export namespace commands { + + /** + * Registers a command that can be invoked via a keyboard shortcut, + * a menu item, an action, or directly. + * + * Registering a command with an existing command identifier twice + * will cause an error. + * + * @param command A unique identifier for the command. + * @param callback A command handler function. + * @param thisArg The `this` context used when invoking the handler function. + * @return Disposable which unregisters this command on disposal. + */ + export function registerCommand(command: string, callback: (...args: any[]) => any, thisArg?: any): Disposable; + + /** + * Registers a text editor command that can be invoked via a keyboard shortcut, + * a menu item, an action, or directly. + * + * Text editor commands are different from ordinary [commands](#commands.registerCommand) as + * they only execute when there is an active editor when the command is called. Also, the + * command handler of an editor command has access to the active editor and to an + * [edit](#TextEditorEdit)-builder. + * + * @param command A unique identifier for the command. + * @param callback A command handler function with access to an [editor](#TextEditor) and an [edit](#TextEditorEdit). + * @param thisArg The `this` context used when invoking the handler function. + * @return Disposable which unregisters this command on disposal. + */ + export function registerTextEditorCommand(command: string, callback: (textEditor: TextEditor, edit: TextEditorEdit, ...args: any[]) => void, thisArg?: any): Disposable; + + /** + * Executes the command denoted by the given command identifier. + * + * * *Note 1:* When executing an editor command not all types are allowed to + * be passed as arguments. Allowed are the primitive types `string`, `boolean`, + * `number`, `undefined`, and `null`, as well as [`Position`](#Position), [`Range`](#Range), [`Uri`](#Uri) and [`Location`](#Location). + * * *Note 2:* There are no restrictions when executing commands that have been contributed + * by extensions. + * + * @param command Identifier of the command to execute. + * @param rest Parameters passed to the command function. + * @return A thenable that resolves to the returned value of the given command. `undefined` when + * the command handler function doesn't return anything. + */ + export function executeCommand(command: string, ...rest: any[]): Thenable; + + /** + * Retrieve the list of all available commands. Commands starting with an underscore are + * treated as internal commands. + * + * @param filterInternal Set `true` to not see internal commands (starting with an underscore) + * @return Thenable that resolves to a list of command ids. + */ + export function getCommands(filterInternal?: boolean): Thenable; + } + + /** + * Represents the state of a window. + */ + export interface WindowState { + + /** + * Whether the current window is focused. + */ + readonly focused: boolean; + } + + /** + * A uri handler is responsible for handling system-wide [uris](#Uri). + * + * @see [window.registerUriHandler](#window.registerUriHandler). + */ + export interface UriHandler { + + /** + * Handle the provided system-wide [uri](#Uri). + * + * @see [window.registerUriHandler](#window.registerUriHandler). + */ + handleUri(uri: Uri): ProviderResult; + } + + /** + * Namespace for dealing with the current window of the editor. That is visible + * and active editors, as well as, UI elements to show messages, selections, and + * asking for user input. + */ + export namespace window { + + /** + * The currently active editor or `undefined`. The active editor is the one + * that currently has focus or, when none has focus, the one that has changed + * input most recently. + */ + export let activeTextEditor: TextEditor | undefined; + + /** + * The currently visible editors or an empty array. + */ + export let visibleTextEditors: TextEditor[]; + + /** + * An [event](#Event) which fires when the [active editor](#window.activeTextEditor) + * has changed. *Note* that the event also fires when the active editor changes + * to `undefined`. + */ + export const onDidChangeActiveTextEditor: Event; + + /** + * An [event](#Event) which fires when the array of [visible editors](#window.visibleTextEditors) + * has changed. + */ + export const onDidChangeVisibleTextEditors: Event; + + /** + * An [event](#Event) which fires when the selection in an editor has changed. + */ + export const onDidChangeTextEditorSelection: Event; + + /** + * An [event](#Event) which fires when the visible ranges of an editor has changed. + */ + export const onDidChangeTextEditorVisibleRanges: Event; + + /** + * An [event](#Event) which fires when the options of an editor have changed. + */ + export const onDidChangeTextEditorOptions: Event; + + /** + * An [event](#Event) which fires when the view column of an editor has changed. + */ + export const onDidChangeTextEditorViewColumn: Event; + + /** + * The currently opened terminals or an empty array. + */ + export const terminals: ReadonlyArray; + + /** + * The currently active terminal or `undefined`. The active terminal is the one that + * currently has focus or most recently had focus. + */ + export const activeTerminal: Terminal | undefined; + + /** + * An [event](#Event) which fires when the [active terminal](#window.activeTerminal) + * has changed. *Note* that the event also fires when the active terminal changes + * to `undefined`. + */ + export const onDidChangeActiveTerminal: Event; + + /** + * An [event](#Event) which fires when a terminal has been created, either through the + * [createTerminal](#window.createTerminal) API or commands. + */ + export const onDidOpenTerminal: Event; + + /** + * An [event](#Event) which fires when a terminal is disposed. + */ + export const onDidCloseTerminal: Event; + + /** + * Represents the current window's state. + */ + export const state: WindowState; + + /** + * An [event](#Event) which fires when the focus state of the current window + * changes. The value of the event represents whether the window is focused. + */ + export const onDidChangeWindowState: Event; + + /** + * Show the given document in a text editor. A [column](#ViewColumn) can be provided + * to control where the editor is being shown. Might change the [active editor](#window.activeTextEditor). + * + * @param document A text document to be shown. + * @param column A view column in which the [editor](#TextEditor) should be shown. The default is the [active](#ViewColumn.Active), other values + * are adjusted to be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) + * to open the editor to the side of the currently active one. + * @param preserveFocus When `true` the editor will not take focus. + * @return A promise that resolves to an [editor](#TextEditor). + */ + export function showTextDocument(document: TextDocument, column?: ViewColumn, preserveFocus?: boolean): Thenable; + + /** + * Show the given document in a text editor. [Options](#TextDocumentShowOptions) can be provided + * to control options of the editor is being shown. Might change the [active editor](#window.activeTextEditor). + * + * @param document A text document to be shown. + * @param options [Editor options](#TextDocumentShowOptions) to configure the behavior of showing the [editor](#TextEditor). + * @return A promise that resolves to an [editor](#TextEditor). + */ + export function showTextDocument(document: TextDocument, options?: TextDocumentShowOptions): Thenable; + + /** + * A short-hand for `openTextDocument(uri).then(document => showTextDocument(document, options))`. + * + * @see [openTextDocument](#openTextDocument) + * + * @param uri A resource identifier. + * @param options [Editor options](#TextDocumentShowOptions) to configure the behavior of showing the [editor](#TextEditor). + * @return A promise that resolves to an [editor](#TextEditor). + */ + export function showTextDocument(uri: Uri, options?: TextDocumentShowOptions): Thenable; + + /** + * Create a TextEditorDecorationType that can be used to add decorations to text editors. + * + * @param options Rendering options for the decoration type. + * @return A new decoration type instance. + */ + export function createTextEditorDecorationType(options: DecorationRenderOptions): TextEditorDecorationType; + + /** + * Show an information message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showInformationMessage(message: string, ...items: string[]): Thenable; + + /** + * Show an information message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param options Configures the behaviour of the message. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showInformationMessage(message: string, options: MessageOptions, ...items: string[]): Thenable; + + /** + * Show an information message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showInformationMessage(message: string, ...items: T[]): Thenable; + + /** + * Show an information message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param options Configures the behaviour of the message. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showInformationMessage(message: string, options: MessageOptions, ...items: T[]): Thenable; + + /** + * Show a warning message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showWarningMessage(message: string, ...items: string[]): Thenable; + + /** + * Show a warning message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param options Configures the behaviour of the message. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showWarningMessage(message: string, options: MessageOptions, ...items: string[]): Thenable; + + /** + * Show a warning message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showWarningMessage(message: string, ...items: T[]): Thenable; + + /** + * Show a warning message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param options Configures the behaviour of the message. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showWarningMessage(message: string, options: MessageOptions, ...items: T[]): Thenable; + + /** + * Show an error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showErrorMessage(message: string, ...items: string[]): Thenable; + + /** + * Show an error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param options Configures the behaviour of the message. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showErrorMessage(message: string, options: MessageOptions, ...items: string[]): Thenable; + + /** + * Show an error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showErrorMessage(message: string, ...items: T[]): Thenable; + + /** + * Show an error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * + * @param message The message to show. + * @param options Configures the behaviour of the message. + * @param items A set of items that will be rendered as actions in the message. + * @return A thenable that resolves to the selected item or `undefined` when being dismissed. + */ + export function showErrorMessage(message: string, options: MessageOptions, ...items: T[]): Thenable; + + /** + * Shows a selection list allowing multiple selections. + * + * @param items An array of strings, or a promise that resolves to an array of strings. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + export function showQuickPick(items: string[] | Thenable, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable; + + /** + * Shows a selection list. + * + * @param items An array of strings, or a promise that resolves to an array of strings. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selection or `undefined`. + */ + export function showQuickPick(items: string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + + /** + * Shows a selection list allowing multiple selections. + * + * @param items An array of items, or a promise that resolves to an array of items. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + export function showQuickPick(items: T[] | Thenable, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable; + + /** + * Shows a selection list. + * + * @param items An array of items, or a promise that resolves to an array of items. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected item or `undefined`. + */ + export function showQuickPick(items: T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + + /** + * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. + * Returns `undefined` if no folder is open. + * + * @param options Configures the behavior of the workspace folder list. + * @return A promise that resolves to the workspace folder or `undefined`. + */ + export function showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions): Thenable; + + /** + * Shows a file open dialog to the user which allows to select a file + * for opening-purposes. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resources or `undefined`. + */ + export function showOpenDialog(options?: OpenDialogOptions): Thenable; + + /** + * Shows a file save dialog to the user which allows to select a file + * for saving-purposes. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resource or `undefined`. + */ + export function showSaveDialog(options?: SaveDialogOptions): Thenable; + + /** + * Opens an input box to ask the user for input. + * + * The returned value will be `undefined` if the input box was canceled (e.g. pressing ESC). Otherwise the + * returned value will be the string typed by the user or an empty string if the user did not type + * anything but dismissed the input box with OK. + * + * @param options Configures the behavior of the input box. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to a string the user provided or to `undefined` in case of dismissal. + */ + export function showInputBox(options?: InputBoxOptions, token?: CancellationToken): Thenable; + + /** + * Creates a [QuickPick](#QuickPick) to let the user pick an item from a list + * of items of type T. + * + * Note that in many cases the more convenient [window.showQuickPick](#window.showQuickPick) + * is easier to use. [window.createQuickPick](#window.createQuickPick) should be used + * when [window.showQuickPick](#window.showQuickPick) does not offer the required flexibility. + * + * @return A new [QuickPick](#QuickPick). + */ + export function createQuickPick(): QuickPick; + + /** + * Creates a [InputBox](#InputBox) to let the user enter some text input. + * + * Note that in many cases the more convenient [window.showInputBox](#window.showInputBox) + * is easier to use. [window.createInputBox](#window.createInputBox) should be used + * when [window.showInputBox](#window.showInputBox) does not offer the required flexibility. + * + * @return A new [InputBox](#InputBox). + */ + export function createInputBox(): InputBox; + + /** + * Creates a new [output channel](#OutputChannel) with the given name. + * + * @param name Human-readable string which will be used to represent the channel in the UI. + */ + export function createOutputChannel(name: string): OutputChannel; + + /** + * Create and show a new webview panel. + * + * @param viewType Identifies the type of the webview panel. + * @param title Title of the panel. + * @param showOptions Where to show the webview in the editor. If preserveFocus is set, the new webview will not take focus. + * @param options Settings for the new panel. + * + * @return New webview panel. + */ + export function createWebviewPanel(viewType: string, title: string, showOptions: ViewColumn | { viewColumn: ViewColumn, preserveFocus?: boolean }, options?: WebviewPanelOptions & WebviewOptions): WebviewPanel; + + /** + * Set a message to the status bar. This is a short hand for the more powerful + * status bar [items](#window.createStatusBarItem). + * + * @param text The message to show, supports icon substitution as in status bar [items](#StatusBarItem.text). + * @param hideAfterTimeout Timeout in milliseconds after which the message will be disposed. + * @return A disposable which hides the status bar message. + */ + export function setStatusBarMessage(text: string, hideAfterTimeout: number): Disposable; + + /** + * Set a message to the status bar. This is a short hand for the more powerful + * status bar [items](#window.createStatusBarItem). + * + * @param text The message to show, supports icon substitution as in status bar [items](#StatusBarItem.text). + * @param hideWhenDone Thenable on which completion (resolve or reject) the message will be disposed. + * @return A disposable which hides the status bar message. + */ + export function setStatusBarMessage(text: string, hideWhenDone: Thenable): Disposable; + + /** + * Set a message to the status bar. This is a short hand for the more powerful + * status bar [items](#window.createStatusBarItem). + * + * *Note* that status bar messages stack and that they must be disposed when no + * longer used. + * + * @param text The message to show, supports icon substitution as in status bar [items](#StatusBarItem.text). + * @return A disposable which hides the status bar message. + */ + export function setStatusBarMessage(text: string): Disposable; + + /** + * ~~Show progress in the Source Control viewlet while running the given callback and while + * its returned promise isn't resolve or rejected.~~ + * + * @deprecated Use `withProgress` instead. + * + * @param task A callback returning a promise. Progress increments can be reported with + * the provided [progress](#Progress)-object. + * @return The thenable the task did return. + */ + export function withScmProgress(task: (progress: Progress) => Thenable): Thenable; + + /** + * Show progress in the editor. Progress is shown while running the given callback + * and while the promise it returned isn't resolved nor rejected. The location at which + * progress should show (and other details) is defined via the passed [`ProgressOptions`](#ProgressOptions). + * + * @param task A callback returning a promise. Progress state can be reported with + * the provided [progress](#Progress)-object. + * + * To report discrete progress, use `increment` to indicate how much work has been completed. Each call with + * a `increment` value will be summed up and reflected as overall progress until 100% is reached (a value of + * e.g. `10` accounts for `10%` of work done). + * Note that currently only `ProgressLocation.Notification` is capable of showing discrete progress. + * + * To monitor if the operation has been cancelled by the user, use the provided [`CancellationToken`](#CancellationToken). + * Note that currently only `ProgressLocation.Notification` is supporting to show a cancel button to cancel the + * long running operation. + * + * @return The thenable the task-callback returned. + */ + export function withProgress(options: ProgressOptions, task: (progress: Progress<{ message?: string; increment?: number }>, token: CancellationToken) => Thenable): Thenable; + + /** + * Creates a status bar [item](#StatusBarItem). + * + * @param alignment The alignment of the item. + * @param priority The priority of the item. Higher values mean the item should be shown more to the left. + * @return A new status bar item. + */ + export function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): StatusBarItem; + + /** + * Creates a [Terminal](#Terminal) with a backing shell process. The cwd of the terminal will be the workspace + * directory if it exists. + * + * @param name Optional human-readable string which will be used to represent the terminal in the UI. + * @param shellPath Optional path to a custom shell executable to be used in the terminal. + * @param shellArgs Optional args for the custom shell executable. A string can be used on Windows only which + * allows specifying shell args in + * [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6). + * @return A new Terminal. + * @throws When running in an environment where a new process cannot be started. + */ + export function createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): Terminal; + + /** + * Creates a [Terminal](#Terminal) with a backing shell process. + * + * @param options A TerminalOptions object describing the characteristics of the new terminal. + * @return A new Terminal. + * @throws When running in an environment where a new process cannot be started. + */ + export function createTerminal(options: TerminalOptions): Terminal; + + /** + * Creates a [Terminal](#Terminal) where an extension controls its input and output. + * + * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * the characteristics of the new terminal. + * @return A new Terminal. + */ + export function createTerminal(options: ExtensionTerminalOptions): Terminal; + + /** + * Register a [TreeDataProvider](#TreeDataProvider) for the view contributed using the extension point `views`. + * This will allow you to contribute data to the [TreeView](#TreeView) and update if the data changes. + * + * **Note:** To get access to the [TreeView](#TreeView) and perform operations on it, use [createTreeView](#window.createTreeView). + * + * @param viewId Id of the view contributed using the extension point `views`. + * @param treeDataProvider A [TreeDataProvider](#TreeDataProvider) that provides tree data for the view + */ + export function registerTreeDataProvider(viewId: string, treeDataProvider: TreeDataProvider): Disposable; + + /** + * Create a [TreeView](#TreeView) for the view contributed using the extension point `views`. + * @param viewId Id of the view contributed using the extension point `views`. + * @param options Options for creating the [TreeView](#TreeView) + * @returns a [TreeView](#TreeView). + */ + export function createTreeView(viewId: string, options: TreeViewOptions): TreeView; + + /** + * Registers a [uri handler](#UriHandler) capable of handling system-wide [uris](#Uri). + * In case there are multiple windows open, the topmost window will handle the uri. + * A uri handler is scoped to the extension it is contributed from; it will only + * be able to handle uris which are directed to the extension itself. A uri must respect + * the following rules: + * + * - The uri-scheme must be `vscode.env.uriScheme`; + * - The uri-authority must be the extension id (e.g. `my.extension`); + * - The uri-path, -query and -fragment parts are arbitrary. + * + * For example, if the `my.extension` extension registers a uri handler, it will only + * be allowed to handle uris with the prefix `product-name://my.extension`. + * + * An extension can only register a single uri handler in its entire activation lifetime. + * + * * *Note:* There is an activation event `onUri` that fires when a uri directed for + * the current extension is about to be handled. + * + * @param handler The uri handler to register for this extension. + */ + export function registerUriHandler(handler: UriHandler): Disposable; + + /** + * Registers a webview panel serializer. + * + * Extensions that support reviving should have an `"onWebviewPanel:viewType"` activation event and + * make sure that [registerWebviewPanelSerializer](#registerWebviewPanelSerializer) is called during activation. + * + * Only a single serializer may be registered at a time for a given `viewType`. + * + * @param viewType Type of the webview panel that can be serialized. + * @param serializer Webview serializer. + */ + export function registerWebviewPanelSerializer(viewType: string, serializer: WebviewPanelSerializer): Disposable; + + /** + * Register a provider for custom editors for the `viewType` contributed by the `customEditors` extension point. + * + * When a custom editor is opened, VS Code fires an `onCustomEditor:viewType` activation event. Your extension + * must register a [`CustomTextEditorProvider`](#CustomTextEditorProvider), [`CustomReadonlyEditorProvider`](#CustomReadonlyEditorProvider), + * [`CustomEditorProvider`](#CustomEditorProvider)for `viewType` as part of activation. + * + * @param viewType Unique identifier for the custom editor provider. This should match the `viewType` from the + * `customEditors` contribution point. + * @param provider Provider that resolves custom editors. + * @param options Options for the provider. + * + * @return Disposable that unregisters the provider. + */ + export function registerCustomEditorProvider(viewType: string, provider: CustomTextEditorProvider | CustomReadonlyEditorProvider | CustomEditorProvider, options?: { + /** + * Content settings for the webview panels created for this custom editor. + */ + readonly webviewOptions?: WebviewPanelOptions; + + /** + * Only applies to `CustomReadonlyEditorProvider | CustomEditorProvider`. + * + * Indicates that the provider allows multiple editor instances to be open at the same time for + * the same resource. + * + * By default, VS Code only allows one editor instance to be open at a time for each resource. If the + * user tries to open a second editor instance for the resource, the first one is instead moved to where + * the second one was to be opened. + * + * When `supportsMultipleEditorsPerDocument` is enabled, users can split and create copies of the custom + * editor. In this case, the custom editor must make sure it can properly synchronize the states of all + * editor instances for a resource so that they are consistent. + */ + readonly supportsMultipleEditorsPerDocument?: boolean; + }): Disposable; + + /** + * The currently active color theme as configured in the settings. The active + * theme can be changed via the `workbench.colorTheme` setting. + */ + export let activeColorTheme: ColorTheme; + + /** + * An [event](#Event) which fires when the active color theme is changed or has changes. + */ + export const onDidChangeActiveColorTheme: Event; + } + + /** + * Options for creating a [TreeView](#TreeView) + */ + export interface TreeViewOptions { + + /** + * A data provider that provides tree data. + */ + treeDataProvider: TreeDataProvider; + + /** + * Whether to show collapse all action or not. + */ + showCollapseAll?: boolean; + + /** + * Whether the tree supports multi-select. When the tree supports multi-select and a command is executed from the tree, + * the first argument to the command is the tree item that the command was executed on and the second argument is an + * array containing all selected tree items. + */ + canSelectMany?: boolean; + } + + /** + * The event that is fired when an element in the [TreeView](#TreeView) is expanded or collapsed + */ + export interface TreeViewExpansionEvent { + + /** + * Element that is expanded or collapsed. + */ + readonly element: T; + + } + + /** + * The event that is fired when there is a change in [tree view's selection](#TreeView.selection) + */ + export interface TreeViewSelectionChangeEvent { + + /** + * Selected elements. + */ + readonly selection: T[]; + + } + + /** + * The event that is fired when there is a change in [tree view's visibility](#TreeView.visible) + */ + export interface TreeViewVisibilityChangeEvent { + + /** + * `true` if the [tree view](#TreeView) is visible otherwise `false`. + */ + readonly visible: boolean; + + } + + /** + * Represents a Tree view + */ + export interface TreeView extends Disposable { + + /** + * Event that is fired when an element is expanded + */ + readonly onDidExpandElement: Event>; + + /** + * Event that is fired when an element is collapsed + */ + readonly onDidCollapseElement: Event>; + + /** + * Currently selected elements. + */ + readonly selection: T[]; + + /** + * Event that is fired when the [selection](#TreeView.selection) has changed + */ + readonly onDidChangeSelection: Event>; + + /** + * `true` if the [tree view](#TreeView) is visible otherwise `false`. + */ + readonly visible: boolean; + + /** + * Event that is fired when [visibility](#TreeView.visible) has changed + */ + readonly onDidChangeVisibility: Event; + + /** + * An optional human-readable message that will be rendered in the view. + * Setting the message to null, undefined, or empty string will remove the message from the view. + */ + message?: string; + + /** + * The tree view title is initially taken from the extension package.json + * Changes to the title property will be properly reflected in the UI in the title of the view. + */ + title?: string; + + /** + * Reveals the given element in the tree view. + * If the tree view is not visible then the tree view is shown and element is revealed. + * + * By default revealed element is selected. + * In order to not to select, set the option `select` to `false`. + * In order to focus, set the option `focus` to `true`. + * In order to expand the revealed element, set the option `expand` to `true`. To expand recursively set `expand` to the number of levels to expand. + * **NOTE:** You can expand only to 3 levels maximum. + * + * **NOTE:** The [TreeDataProvider](#TreeDataProvider) that the `TreeView` [is registered with](#window.createTreeView) with must implement [getParent](#TreeDataProvider.getParent) method to access this API. + */ + reveal(element: T, options?: { select?: boolean, focus?: boolean, expand?: boolean | number }): Thenable; + } + + /** + * A data provider that provides tree data + */ + export interface TreeDataProvider { + /** + * An optional event to signal that an element or root has changed. + * This will trigger the view to update the changed element/root and its children recursively (if shown). + * To signal that root has changed, do not pass any argument or pass `undefined` or `null`. + */ + onDidChangeTreeData?: Event; + + /** + * Get [TreeItem](#TreeItem) representation of the `element` + * + * @param element The element for which [TreeItem](#TreeItem) representation is asked for. + * @return [TreeItem](#TreeItem) representation of the element + */ + getTreeItem(element: T): TreeItem | Thenable; + + /** + * Get the children of `element` or root if no element is passed. + * + * @param element The element from which the provider gets children. Can be `undefined`. + * @return Children of `element` or root if no element is passed. + */ + getChildren(element?: T): ProviderResult; + + /** + * Optional method to return the parent of `element`. + * Return `null` or `undefined` if `element` is a child of root. + * + * **NOTE:** This method should be implemented in order to access [reveal](#TreeView.reveal) API. + * + * @param element The element for which the parent has to be returned. + * @return Parent of `element`. + */ + getParent?(element: T): ProviderResult; + } + + export class TreeItem { + /** + * A human-readable string describing this item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri). + */ + label?: string; + + /** + * Optional id for the tree item that has to be unique across tree. The id is used to preserve the selection and expansion state of the tree item. + * + * If not provided, an id is generated using the tree item's label. **Note** that when labels change, ids will change and that selection and expansion state cannot be kept stable anymore. + */ + id?: string; + + /** + * The icon path or [ThemeIcon](#ThemeIcon) for the tree item. + * When `falsy`, [Folder Theme Icon](#ThemeIcon.Folder) is assigned, if item is collapsible otherwise [File Theme Icon](#ThemeIcon.File). + * When a file or folder [ThemeIcon](#ThemeIcon) is specified, icon is derived from the current file icon theme for the specified theme icon using [resourceUri](#TreeItem.resourceUri) (if provided). + */ + iconPath?: string | Uri | { light: string | Uri; dark: string | Uri } | ThemeIcon; + + /** + * A human-readable string which is rendered less prominent. + * When `true`, it is derived from [resourceUri](#TreeItem.resourceUri) and when `falsy`, it is not shown. + */ + description?: string | boolean; + + /** + * The [uri](#Uri) of the resource representing this item. + * + * Will be used to derive the [label](#TreeItem.label), when it is not provided. + * Will be used to derive the icon from current file icon theme, when [iconPath](#TreeItem.iconPath) has [ThemeIcon](#ThemeIcon) value. + */ + resourceUri?: Uri; + + /** + * The tooltip text when you hover over this item. + */ + tooltip?: string | undefined; + + /** + * The [command](#Command) that should be executed when the tree item is selected. + */ + command?: Command; + + /** + * [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. + */ + collapsibleState?: TreeItemCollapsibleState; + + /** + * Context value of the tree item. This can be used to contribute item specific actions in the tree. + * For example, a tree item is given a context value as `folder`. When contributing actions to `view/item/context` + * using `menus` extension point, you can specify context value for key `viewItem` in `when` expression like `viewItem == folder`. + * ``` + * "contributes": { + * "menus": { + * "view/item/context": [ + * { + * "command": "extension.deleteFolder", + * "when": "viewItem == folder" + * } + * ] + * } + * } + * ``` + * This will show action `extension.deleteFolder` only for items with `contextValue` is `folder`. + */ + contextValue?: string; + + /** + * Accessibility information used when screen reader interacts with this tree item. + * Generally, a TreeItem has no need to set the `role` of the accessibilityInformation; + * however, there are cases where a TreeItem is not displayed in a tree-like way where setting the `role` may make sense. + */ + accessibilityInformation?: AccessibilityInformation; + + /** + * @param label A human-readable string describing this item + * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + */ + constructor(label: string, collapsibleState?: TreeItemCollapsibleState); + + /** + * @param resourceUri The [uri](#Uri) of the resource representing this item. + * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + */ + constructor(resourceUri: Uri, collapsibleState?: TreeItemCollapsibleState); + } + + /** + * Collapsible state of the tree item + */ + export enum TreeItemCollapsibleState { + /** + * Determines an item can be neither collapsed nor expanded. Implies it has no children. + */ + None = 0, + /** + * Determines an item is collapsed + */ + Collapsed = 1, + /** + * Determines an item is expanded + */ + Expanded = 2 + } + + /** + * Value-object describing what options a terminal should use. + */ + export interface TerminalOptions { + /** + * A human-readable string which will be used to represent the terminal in the UI. + */ + name?: string; + + /** + * A path to a custom shell executable to be used in the terminal. + */ + shellPath?: string; + + /** + * Args for the custom shell executable. A string can be used on Windows only which allows + * specifying shell args in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6). + */ + shellArgs?: string[] | string; + + /** + * A path or Uri for the current working directory to be used for the terminal. + */ + cwd?: string | Uri; + + /** + * Object with environment variables that will be added to the VS Code process. + */ + env?: { [key: string]: string | null }; + + /** + * Whether the terminal process environment should be exactly as provided in + * `TerminalOptions.env`. When this is false (default), the environment will be based on the + * window's environment and also apply configured platform settings like + * `terminal.integrated.windows.env` on top. When this is true, the complete environment + * must be provided as nothing will be inherited from the process or any configuration. + */ + strictEnv?: boolean; + + /** + * When enabled the terminal will run the process as normal but not be surfaced to the user + * until `Terminal.show` is called. The typical usage for this is when you need to run + * something that may need interactivity but only want to tell the user about it when + * interaction is needed. Note that the terminals will still be exposed to all extensions + * as normal. + */ + hideFromUser?: boolean; + } + + /** + * Value-object describing what options a virtual process terminal should use. + */ + export interface ExtensionTerminalOptions { + /** + * A human-readable string which will be used to represent the terminal in the UI. + */ + name: string; + + /** + * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * control a terminal. + */ + pty: Pseudoterminal; + } + + /** + * Defines the interface of a terminal pty, enabling extensions to control a terminal. + */ + interface Pseudoterminal { + /** + * An event that when fired will write data to the terminal. Unlike + * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying child + * pseudo-device (the child), this will write the text to parent pseudo-device (the + * _terminal_ itself). + * + * Note writing `\n` will just move the cursor down 1 row, you need to write `\r` as well + * to move the cursor to the left-most cell. + * + * **Example:** Write red text to the terminal + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` + * + * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk + * ```typescript + * writeEmitter.fire('\x1b[10;20H*'); + * ``` + */ + onDidWrite: Event; + + /** + * An event that when fired allows overriding the [dimensions](#Pseudoterminal.setDimensions) of the + * terminal. Note that when set, the overridden dimensions will only take effect when they + * are lower than the actual dimensions of the terminal (ie. there will never be a scroll + * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to + * the size of the panel). + * + * **Example:** Override the dimensions of a terminal to 20 columns and 10 rows + * ```typescript + * const dimensionsEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidOverrideDimensions: dimensionsEmitter.event, + * open: () => { + * dimensionsEmitter.fire({ + * columns: 20, + * rows: 10 + * }); + * }, + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` + */ + onDidOverrideDimensions?: Event; + + /** + * An event that when fired will signal that the pty is closed and dispose of the terminal. + * + * A number can be used to provide an exit code for the terminal. Exit codes must be + * positive and a non-zero exit codes signals failure which shows a notification for a + * regular terminal and allows dependent tasks to proceed when used with the + * `CustomExecution` API. + * + * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const closeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidClose: closeEmitter.event, + * open: () => writeEmitter.fire('Press y to exit successfully'), + * close: () => {}, + * handleInput: data => { + * if (data !== 'y') { + * vscode.window.showInformationMessage('Something went wrong'); + * } + * closeEmitter.fire(); + * } + * }; + * vscode.window.createTerminal({ name: 'Exit example', pty }); + * ``` + */ + onDidClose?: Event; + + /** + * Implement to handle when the pty is open and ready to start firing events. + * + * @param initialDimensions The dimensions of the terminal, this will be undefined if the + * terminal panel has not been opened before this is called. + */ + open(initialDimensions: TerminalDimensions | undefined): void; + + /** + * Implement to handle when the terminal is closed by an act of the user. + */ + close(): void; + + /** + * Implement to handle incoming keystrokes in the terminal or when an extension calls + * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into + * their corresponding VT sequence representation. + * + * @param data The incoming data. + * + * **Example:** Echo input in the terminal. The sequence for enter (`\r`) is translated to + * CRLF to go to a new line and move the cursor to the start of the line. + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => {}, + * close: () => {}, + * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) + * }; + * vscode.window.createTerminal({ name: 'Local echo', pty }); + * ``` + */ + handleInput?(data: string): void; + + /** + * Implement to handle when the number of rows and columns that fit into the terminal panel + * changes, for example when font size changes or when the panel is resized. The initial + * state of a terminal's dimensions should be treated as `undefined` until this is triggered + * as the size of a terminal isn't know until it shows up in the user interface. + * + * When dimensions are overridden by + * [onDidOverrideDimensions](#Pseudoterminal.onDidOverrideDimensions), `setDimensions` will + * continue to be called with the regular panel dimensions, allowing the extension continue + * to react dimension changes. + * + * @param dimensions The new dimensions. + */ + setDimensions?(dimensions: TerminalDimensions): void; + } + + /** + * Represents the dimensions of a terminal. + */ + export interface TerminalDimensions { + /** + * The number of columns in the terminal. + */ + readonly columns: number; + + /** + * The number of rows in the terminal. + */ + readonly rows: number; + } + + /** + * Represents how a terminal exited. + */ + export interface TerminalExitStatus { + /** + * The exit code that a terminal exited with, it can have the following values: + * - Zero: the terminal process or custom execution succeeded. + * - Non-zero: the terminal process or custom execution failed. + * - `undefined`: the user forcibly closed the terminal or a custom execution exited + * without providing an exit code. + */ + readonly code: number | undefined; + } + + /** + * A type of mutation that can be applied to an environment variable. + */ + export enum EnvironmentVariableMutatorType { + /** + * Replace the variable's existing value. + */ + Replace = 1, + /** + * Append to the end of the variable's existing value. + */ + Append = 2, + /** + * Prepend to the start of the variable's existing value. + */ + Prepend = 3 + } + + /** + * A type of mutation and its value to be applied to an environment variable. + */ + export interface EnvironmentVariableMutator { + /** + * The type of mutation that will occur to the variable. + */ + readonly type: EnvironmentVariableMutatorType; + + /** + * The value to use for the variable. + */ + readonly value: string; + } + + /** + * A collection of mutations that an extension can apply to a process environment. + */ + export interface EnvironmentVariableCollection { + /** + * Whether the collection should be cached for the workspace and applied to the terminal + * across window reloads. When true the collection will be active immediately such when the + * window reloads. Additionally, this API will return the cached version if it exists. The + * collection will be invalidated when the extension is uninstalled or when the collection + * is cleared. Defaults to true. + */ + persistent: boolean; + + /** + * Replace an environment variable with a value. + * + * Note that an extension can only make a single change to any one variable, so this will + * overwrite any previous calls to replace, append or prepend. + * + * @param variable The variable to replace. + * @param value The value to replace the variable with. + */ + replace(variable: string, value: string): void; + + /** + * Append a value to an environment variable. + * + * Note that an extension can only make a single change to any one variable, so this will + * overwrite any previous calls to replace, append or prepend. + * + * @param variable The variable to append to. + * @param value The value to append to the variable. + */ + append(variable: string, value: string): void; + + /** + * Prepend a value to an environment variable. + * + * Note that an extension can only make a single change to any one variable, so this will + * overwrite any previous calls to replace, append or prepend. + * + * @param variable The variable to prepend. + * @param value The value to prepend to the variable. + */ + prepend(variable: string, value: string): void; + + /** + * Gets the mutator that this collection applies to a variable, if any. + * + * @param variable The variable to get the mutator for. + */ + get(variable: string): EnvironmentVariableMutator | undefined; + + /** + * Iterate over each mutator in this collection. + * + * @param callback Function to execute for each entry. + * @param thisArg The `this` context used when invoking the handler function. + */ + forEach(callback: (variable: string, mutator: EnvironmentVariableMutator, collection: EnvironmentVariableCollection) => any, thisArg?: any): void; + + /** + * Deletes this collection's mutator for a variable. + * + * @param variable The variable to delete the mutator for. + */ + delete(variable: string): void; + + /** + * Clears all mutators from this collection. + */ + clear(): void; + } + + /** + * A location in the editor at which progress information can be shown. It depends on the + * location how progress is visually represented. + */ + export enum ProgressLocation { + + /** + * Show progress for the source control viewlet, as overlay for the icon and as progress bar + * inside the viewlet (when visible). Neither supports cancellation nor discrete progress. + */ + SourceControl = 1, + + /** + * Show progress in the status bar of the editor. Neither supports cancellation nor discrete progress. + */ + Window = 10, + + /** + * Show progress as notification with an optional cancel button. Supports to show infinite and discrete progress. + */ + Notification = 15 + } + + /** + * Value-object describing where and how progress should show. + */ + export interface ProgressOptions { + + /** + * The location at which progress should show. + */ + location: ProgressLocation | { viewId: string }; + + /** + * A human-readable string which will be used to describe the + * operation. + */ + title?: string; + + /** + * Controls if a cancel button should show to allow the user to + * cancel the long running operation. Note that currently only + * `ProgressLocation.Notification` is supporting to show a cancel + * button. + */ + cancellable?: boolean; + } + + /** + * A light-weight user input UI that is initially not visible. After + * configuring it through its properties the extension can make it + * visible by calling [QuickInput.show](#QuickInput.show). + * + * There are several reasons why this UI might have to be hidden and + * the extension will be notified through [QuickInput.onDidHide](#QuickInput.onDidHide). + * (Examples include: an explicit call to [QuickInput.hide](#QuickInput.hide), + * the user pressing Esc, some other input UI opening, etc.) + * + * A user pressing Enter or some other gesture implying acceptance + * of the current state does not automatically hide this UI component. + * It is up to the extension to decide whether to accept the user's input + * and if the UI should indeed be hidden through a call to [QuickInput.hide](#QuickInput.hide). + * + * When the extension no longer needs this input UI, it should + * [QuickInput.dispose](#QuickInput.dispose) it to allow for freeing up + * any resources associated with it. + * + * See [QuickPick](#QuickPick) and [InputBox](#InputBox) for concrete UIs. + */ + export interface QuickInput { + + /** + * An optional title. + */ + title: string | undefined; + + /** + * An optional current step count. + */ + step: number | undefined; + + /** + * An optional total step count. + */ + totalSteps: number | undefined; + + /** + * If the UI should allow for user input. Defaults to true. + * + * Change this to false, e.g., while validating user input or + * loading data for the next step in user input. + */ + enabled: boolean; + + /** + * If the UI should show a progress indicator. Defaults to false. + * + * Change this to true, e.g., while loading more data or validating + * user input. + */ + busy: boolean; + + /** + * If the UI should stay open even when loosing UI focus. Defaults to false. + */ + ignoreFocusOut: boolean; + + /** + * Makes the input UI visible in its current configuration. Any other input + * UI will first fire an [QuickInput.onDidHide](#QuickInput.onDidHide) event. + */ + show(): void; + + /** + * Hides this input UI. This will also fire an [QuickInput.onDidHide](#QuickInput.onDidHide) + * event. + */ + hide(): void; + + /** + * An event signaling when this input UI is hidden. + * + * There are several reasons why this UI might have to be hidden and + * the extension will be notified through [QuickInput.onDidHide](#QuickInput.onDidHide). + * (Examples include: an explicit call to [QuickInput.hide](#QuickInput.hide), + * the user pressing Esc, some other input UI opening, etc.) + */ + onDidHide: Event; + + /** + * Dispose of this input UI and any associated resources. If it is still + * visible, it is first hidden. After this call the input UI is no longer + * functional and no additional methods or properties on it should be + * accessed. Instead a new input UI should be created. + */ + dispose(): void; + } + + /** + * A concrete [QuickInput](#QuickInput) to let the user pick an item from a + * list of items of type T. The items can be filtered through a filter text field and + * there is an option [canSelectMany](#QuickPick.canSelectMany) to allow for + * selecting multiple items. + * + * Note that in many cases the more convenient [window.showQuickPick](#window.showQuickPick) + * is easier to use. [window.createQuickPick](#window.createQuickPick) should be used + * when [window.showQuickPick](#window.showQuickPick) does not offer the required flexibility. + */ + export interface QuickPick extends QuickInput { + + /** + * Current value of the filter text. + */ + value: string; + + /** + * Optional placeholder in the filter text. + */ + placeholder: string | undefined; + + /** + * An event signaling when the value of the filter text has changed. + */ + readonly onDidChangeValue: Event; + + /** + * An event signaling when the user indicated acceptance of the selected item(s). + */ + readonly onDidAccept: Event; + + /** + * Buttons for actions in the UI. + */ + buttons: ReadonlyArray; + + /** + * An event signaling when a button was triggered. + */ + readonly onDidTriggerButton: Event; + + /** + * Items to pick from. + */ + items: ReadonlyArray; + + /** + * If multiple items can be selected at the same time. Defaults to false. + */ + canSelectMany: boolean; + + /** + * If the filter text should also be matched against the description of the items. Defaults to false. + */ + matchOnDescription: boolean; + + /** + * If the filter text should also be matched against the detail of the items. Defaults to false. + */ + matchOnDetail: boolean; + + /** + * Active items. This can be read and updated by the extension. + */ + activeItems: ReadonlyArray; + + /** + * An event signaling when the active items have changed. + */ + readonly onDidChangeActive: Event; + + /** + * Selected items. This can be read and updated by the extension. + */ + selectedItems: ReadonlyArray; + + /** + * An event signaling when the selected items have changed. + */ + readonly onDidChangeSelection: Event; + } + + /** + * A concrete [QuickInput](#QuickInput) to let the user input a text value. + * + * Note that in many cases the more convenient [window.showInputBox](#window.showInputBox) + * is easier to use. [window.createInputBox](#window.createInputBox) should be used + * when [window.showInputBox](#window.showInputBox) does not offer the required flexibility. + */ + export interface InputBox extends QuickInput { + + /** + * Current input value. + */ + value: string; + + /** + * Optional placeholder in the filter text. + */ + placeholder: string | undefined; + + /** + * If the input value should be hidden. Defaults to false. + */ + password: boolean; + + /** + * An event signaling when the value has changed. + */ + readonly onDidChangeValue: Event; + + /** + * An event signaling when the user indicated acceptance of the input value. + */ + readonly onDidAccept: Event; + + /** + * Buttons for actions in the UI. + */ + buttons: ReadonlyArray; + + /** + * An event signaling when a button was triggered. + */ + readonly onDidTriggerButton: Event; + + /** + * An optional prompt text providing some ask or explanation to the user. + */ + prompt: string | undefined; + + /** + * An optional validation message indicating a problem with the current input value. + */ + validationMessage: string | undefined; + } + + /** + * Button for an action in a [QuickPick](#QuickPick) or [InputBox](#InputBox). + */ + export interface QuickInputButton { + + /** + * Icon for the button. + */ + readonly iconPath: Uri | { light: Uri; dark: Uri } | ThemeIcon; + + /** + * An optional tooltip. + */ + readonly tooltip?: string | undefined; + } + + /** + * Predefined buttons for [QuickPick](#QuickPick) and [InputBox](#InputBox). + */ + export class QuickInputButtons { + + /** + * A back button for [QuickPick](#QuickPick) and [InputBox](#InputBox). + * + * When a navigation 'back' button is needed this one should be used for consistency. + * It comes with a predefined icon, tooltip and location. + */ + static readonly Back: QuickInputButton; + + /** + * @hidden + */ + private constructor(); + } + + /** + * An event describing an individual change in the text of a [document](#TextDocument). + */ + export interface TextDocumentContentChangeEvent { + /** + * The range that got replaced. + */ + readonly range: Range; + /** + * The offset of the range that got replaced. + */ + readonly rangeOffset: number; + /** + * The length of the range that got replaced. + */ + readonly rangeLength: number; + /** + * The new text for the range. + */ + readonly text: string; + } + + /** + * An event describing a transactional [document](#TextDocument) change. + */ + export interface TextDocumentChangeEvent { + + /** + * The affected document. + */ + readonly document: TextDocument; + + /** + * An array of content changes. + */ + readonly contentChanges: ReadonlyArray; + } + + /** + * Represents reasons why a text document is saved. + */ + export enum TextDocumentSaveReason { + + /** + * Manually triggered, e.g. by the user pressing save, by starting debugging, + * or by an API call. + */ + Manual = 1, + + /** + * Automatic after a delay. + */ + AfterDelay = 2, + + /** + * When the editor lost focus. + */ + FocusOut = 3 + } + + /** + * An event that is fired when a [document](#TextDocument) will be saved. + * + * To make modifications to the document before it is being saved, call the + * [`waitUntil`](#TextDocumentWillSaveEvent.waitUntil)-function with a thenable + * that resolves to an array of [text edits](#TextEdit). + */ + export interface TextDocumentWillSaveEvent { + + /** + * The document that will be saved. + */ + readonly document: TextDocument; + + /** + * The reason why save was triggered. + */ + readonly reason: TextDocumentSaveReason; + + /** + * Allows to pause the event loop and to apply [pre-save-edits](#TextEdit). + * Edits of subsequent calls to this function will be applied in order. The + * edits will be *ignored* if concurrent modifications of the document happened. + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillSaveTextDocument(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that resolves to [pre-save-edits](#TextEdit). + */ + waitUntil(thenable: Thenable): void; + + /** + * Allows to pause the event loop until the provided thenable resolved. + * + * *Note:* This function can only be called during event dispatch. + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + } + + /** + * An event that is fired when files are going to be created. + * + * To make modifications to the workspace before the files are created, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ + export interface FileWillCreateEvent { + + /** + * The files that are going to be created. + */ + readonly files: ReadonlyArray; + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + + /** + * Allows to pause the event until the provided thenable resolves. + * + * *Note:* This function can only be called during event dispatch. + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + } + + /** + * An event that is fired after files are created. + */ + export interface FileCreateEvent { + + /** + * The files that got created. + */ + readonly files: ReadonlyArray; + } + + /** + * An event that is fired when files are going to be deleted. + * + * To make modifications to the workspace before the files are deleted, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ + export interface FileWillDeleteEvent { + + /** + * The files that are going to be deleted. + */ + readonly files: ReadonlyArray; + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + + /** + * Allows to pause the event until the provided thenable resolves. + * + * *Note:* This function can only be called during event dispatch. + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + } + + /** + * An event that is fired after files are deleted. + */ + export interface FileDeleteEvent { + + /** + * The files that got deleted. + */ + readonly files: ReadonlyArray; + } + + /** + * An event that is fired when files are going to be renamed. + * + * To make modifications to the workspace before the files are renamed, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ + export interface FileWillRenameEvent { + + /** + * The files that are going to be renamed. + */ + readonly files: ReadonlyArray<{ oldUri: Uri, newUri: Uri }>; + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + + /** + * Allows to pause the event until the provided thenable resolves. + * + * *Note:* This function can only be called during event dispatch. + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void; + } + + /** + * An event that is fired after files are renamed. + */ + export interface FileRenameEvent { + + /** + * The files that got renamed. + */ + readonly files: ReadonlyArray<{ oldUri: Uri, newUri: Uri }>; + } + + /** + * An event describing a change to the set of [workspace folders](#workspace.workspaceFolders). + */ + export interface WorkspaceFoldersChangeEvent { + /** + * Added workspace folders. + */ + readonly added: ReadonlyArray; + + /** + * Removed workspace folders. + */ + readonly removed: ReadonlyArray; + } + + /** + * A workspace folder is one of potentially many roots opened by the editor. All workspace folders + * are equal which means there is no notion of an active or primary workspace folder. + */ + export interface WorkspaceFolder { + + /** + * The associated uri for this workspace folder. + * + * *Note:* The [Uri](#Uri)-type was intentionally chosen such that future releases of the editor can support + * workspace folders that are not stored on the local disk, e.g. `ftp://server/workspaces/foo`. + */ + readonly uri: Uri; + + /** + * The name of this workspace folder. Defaults to + * the basename of its [uri-path](#Uri.path) + */ + readonly name: string; + + /** + * The ordinal number of this workspace folder. + */ + readonly index: number; + } + + /** + * Namespace for dealing with the current workspace. A workspace is the representation + * of the folder that has been opened. There is no workspace when just a file but not a + * folder has been opened. + * + * The workspace offers support for [listening](#workspace.createFileSystemWatcher) to fs + * events and for [finding](#workspace.findFiles) files. Both perform well and run _outside_ + * the editor-process so that they should be always used instead of nodejs-equivalents. + */ + export namespace workspace { + + /** + * A [file system](#FileSystem) instance that allows to interact with local and remote + * files, e.g. `vscode.workspace.fs.readDirectory(someUri)` allows to retrieve all entries + * of a directory or `vscode.workspace.fs.stat(anotherUri)` returns the meta data for a + * file. + */ + export const fs: FileSystem; + + /** + * ~~The folder that is open in the editor. `undefined` when no folder + * has been opened.~~ + * + * @deprecated Use [`workspaceFolders`](#workspace.workspaceFolders) instead. + */ + export const rootPath: string | undefined; + + /** + * List of workspace folders or `undefined` when no folder is open. + * *Note* that the first entry corresponds to the value of `rootPath`. + */ + export const workspaceFolders: ReadonlyArray | undefined; + + /** + * The name of the workspace. `undefined` when no folder + * has been opened. + */ + export const name: string | undefined; + + /** + * The location of the workspace file, for example: + * + * `file:///Users/name/Development/myProject.code-workspace` + * + * or + * + * `untitled:1555503116870` + * + * for a workspace that is untitled and not yet saved. + * + * Depending on the workspace that is opened, the value will be: + * * `undefined` when no workspace or a single folder is opened + * * the path of the workspace file as `Uri` otherwise. if the workspace + * is untitled, the returned URI will use the `untitled:` scheme + * + * The location can e.g. be used with the `vscode.openFolder` command to + * open the workspace again after it has been closed. + * + * **Example:** + * ```typescript + * vscode.commands.executeCommand('vscode.openFolder', uriOfWorkspace); + * ``` + * + * **Note:** it is not advised to use `workspace.workspaceFile` to write + * configuration data into the file. You can use `workspace.getConfiguration().update()` + * for that purpose which will work both when a single folder is opened as + * well as an untitled or saved workspace. + */ + export const workspaceFile: Uri | undefined; + + /** + * An event that is emitted when a workspace folder is added or removed. + */ + export const onDidChangeWorkspaceFolders: Event; + + /** + * Returns the [workspace folder](#WorkspaceFolder) that contains a given uri. + * * returns `undefined` when the given uri doesn't match any workspace folder + * * returns the *input* when the given uri is a workspace folder itself + * + * @param uri An uri. + * @return A workspace folder or `undefined` + */ + export function getWorkspaceFolder(uri: Uri): WorkspaceFolder | undefined; + + /** + * Returns a path that is relative to the workspace folder or folders. + * + * When there are no [workspace folders](#workspace.workspaceFolders) or when the path + * is not contained in them, the input is returned. + * + * @param pathOrUri A path or uri. When a uri is given its [fsPath](#Uri.fsPath) is used. + * @param includeWorkspaceFolder When `true` and when the given path is contained inside a + * workspace folder the name of the workspace is prepended. Defaults to `true` when there are + * multiple workspace folders and `false` otherwise. + * @return A path relative to the root or the input. + */ + export function asRelativePath(pathOrUri: string | Uri, includeWorkspaceFolder?: boolean): string; + + /** + * This method replaces `deleteCount` [workspace folders](#workspace.workspaceFolders) starting at index `start` + * by an optional set of `workspaceFoldersToAdd` on the `vscode.workspace.workspaceFolders` array. This "splice" + * behavior can be used to add, remove and change workspace folders in a single operation. + * + * If the first workspace folder is added, removed or changed, the currently executing extensions (including the + * one that called this method) will be terminated and restarted so that the (deprecated) `rootPath` property is + * updated to point to the first workspace folder. + * + * Use the [`onDidChangeWorkspaceFolders()`](#onDidChangeWorkspaceFolders) event to get notified when the + * workspace folders have been updated. + * + * **Example:** adding a new workspace folder at the end of workspace folders + * ```typescript + * workspace.updateWorkspaceFolders(workspace.workspaceFolders ? workspace.workspaceFolders.length : 0, null, { uri: ...}); + * ``` + * + * **Example:** removing the first workspace folder + * ```typescript + * workspace.updateWorkspaceFolders(0, 1); + * ``` + * + * **Example:** replacing an existing workspace folder with a new one + * ```typescript + * workspace.updateWorkspaceFolders(0, 1, { uri: ...}); + * ``` + * + * It is valid to remove an existing workspace folder and add it again with a different name + * to rename that folder. + * + * **Note:** it is not valid to call [updateWorkspaceFolders()](#updateWorkspaceFolders) multiple times + * without waiting for the [`onDidChangeWorkspaceFolders()`](#onDidChangeWorkspaceFolders) to fire. + * + * @param start the zero-based location in the list of currently opened [workspace folders](#WorkspaceFolder) + * from which to start deleting workspace folders. + * @param deleteCount the optional number of workspace folders to remove. + * @param workspaceFoldersToAdd the optional variable set of workspace folders to add in place of the deleted ones. + * Each workspace is identified with a mandatory URI and an optional name. + * @return true if the operation was successfully started and false otherwise if arguments were used that would result + * in invalid workspace folder state (e.g. 2 folders with the same URI). + */ + export function updateWorkspaceFolders(start: number, deleteCount: number | undefined | null, ...workspaceFoldersToAdd: { uri: Uri, name?: string }[]): boolean; + + /** + * Creates a file system watcher. + * + * A glob pattern that filters the file events on their absolute path must be provided. Optionally, + * flags to ignore certain kinds of events can be provided. To stop listening to events the watcher must be disposed. + * + * *Note* that only files within the current [workspace folders](#workspace.workspaceFolders) can be watched. + * + * @param globPattern A [glob pattern](#GlobPattern) that is applied to the absolute paths of created, changed, + * and deleted files. Use a [relative pattern](#RelativePattern) to limit events to a certain [workspace folder](#WorkspaceFolder). + * @param ignoreCreateEvents Ignore when files have been created. + * @param ignoreChangeEvents Ignore when files have been changed. + * @param ignoreDeleteEvents Ignore when files have been deleted. + * @return A new file system watcher instance. + */ + export function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; + + /** + * Find files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * + * @sample `findFiles('**​/*.js', '**​/node_modules/**', 10)` + * @param include A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. Use a [relative pattern](#RelativePattern) + * to restrict the search results to a [workspace folder](#WorkspaceFolder). + * @param exclude A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. When `undefined` only default excludes will + * apply, when `null` no excludes will apply. + * @param maxResults An upper-bound for the result. + * @param token A token that can be used to signal cancellation to the underlying search engine. + * @return A thenable that resolves to an array of resource identifiers. Will return no results if no + * [workspace folders](#workspace.workspaceFolders) are opened. + */ + export function findFiles(include: GlobPattern, exclude?: GlobPattern | null, maxResults?: number, token?: CancellationToken): Thenable; + + /** + * Save all dirty files. + * + * @param includeUntitled Also save files that have been created during this session. + * @return A thenable that resolves when the files have been saved. + */ + export function saveAll(includeUntitled?: boolean): Thenable; + + /** + * Make changes to one or many resources or create, delete, and rename resources as defined by the given + * [workspace edit](#WorkspaceEdit). + * + * All changes of a workspace edit are applied in the same order in which they have been added. If + * multiple textual inserts are made at the same position, these strings appear in the resulting text + * in the order the 'inserts' were made, unless that are interleaved with resource edits. Invalid sequences + * like 'delete file a' -> 'insert text in file a' cause failure of the operation. + * + * When applying a workspace edit that consists only of text edits an 'all-or-nothing'-strategy is used. + * A workspace edit with resource creations or deletions aborts the operation, e.g. consecutive edits will + * not be attempted, when a single edit fails. + * + * @param edit A workspace edit. + * @return A thenable that resolves when the edit could be applied. + */ + export function applyEdit(edit: WorkspaceEdit): Thenable; + + /** + * All text documents currently known to the system. + */ + export const textDocuments: ReadonlyArray; + + /** + * Opens a document. Will return early if this document is already open. Otherwise + * the document is loaded and the [didOpen](#workspace.onDidOpenTextDocument)-event fires. + * + * The document is denoted by an [uri](#Uri). Depending on the [scheme](#Uri.scheme) the + * following rules apply: + * * `file`-scheme: Open a file on disk, will be rejected if the file does not exist or cannot be loaded. + * * `untitled`-scheme: A new file that should be saved on disk, e.g. `untitled:c:\frodo\new.js`. The language + * will be derived from the file name. + * * For all other schemes contributed [text document content providers](#TextDocumentContentProvider) and + * [file system providers](#FileSystemProvider) are consulted. + * + * *Note* that the lifecycle of the returned document is owned by the editor and not by the extension. That means an + * [`onDidClose`](#workspace.onDidCloseTextDocument)-event can occur at any time after opening it. + * + * @param uri Identifies the resource to open. + * @return A promise that resolves to a [document](#TextDocument). + */ + export function openTextDocument(uri: Uri): Thenable; + + /** + * A short-hand for `openTextDocument(Uri.file(fileName))`. + * + * @see [openTextDocument](#openTextDocument) + * @param fileName A name of a file on disk. + * @return A promise that resolves to a [document](#TextDocument). + */ + export function openTextDocument(fileName: string): Thenable; + + /** + * Opens an untitled text document. The editor will prompt the user for a file + * path when the document is to be saved. The `options` parameter allows to + * specify the *language* and/or the *content* of the document. + * + * @param options Options to control how the document will be created. + * @return A promise that resolves to a [document](#TextDocument). + */ + export function openTextDocument(options?: { language?: string; content?: string; }): Thenable; + + /** + * Register a text document content provider. + * + * Only one provider can be registered per scheme. + * + * @param scheme The uri-scheme to register for. + * @param provider A content provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; + + /** + * An event that is emitted when a [text document](#TextDocument) is opened or when the language id + * of a text document [has been changed](#languages.setTextDocumentLanguage). + * + * To add an event listener when a visible text document is opened, use the [TextEditor](#TextEditor) events in the + * [window](#window) namespace. Note that: + * + * - The event is emitted before the [document](#TextDocument) is updated in the + * [active text editor](#window.activeTextEditor) + * - When a [text document](#TextDocument) is already open (e.g.: open in another [visible text editor](#window.visibleTextEditors)) this event is not emitted + * + */ + export const onDidOpenTextDocument: Event; + + /** + * An event that is emitted when a [text document](#TextDocument) is disposed or when the language id + * of a text document [has been changed](#languages.setTextDocumentLanguage). + * + * *Note 1:* There is no guarantee that this event fires when an editor tab is closed, use the + * [`onDidChangeVisibleTextEditors`](#window.onDidChangeVisibleTextEditors)-event to know when editors change. + * + * *Note 2:* A document can be open but not shown in an editor which means this event can fire + * for a document that has not been shown in an editor. + */ + export const onDidCloseTextDocument: Event; + + /** + * An event that is emitted when a [text document](#TextDocument) is changed. This usually happens + * when the [contents](#TextDocument.getText) changes but also when other things like the + * [dirty](#TextDocument.isDirty)-state changes. + */ + export const onDidChangeTextDocument: Event; + + /** + * An event that is emitted when a [text document](#TextDocument) will be saved to disk. + * + * *Note 1:* Subscribers can delay saving by registering asynchronous work. For the sake of data integrity the editor + * might save without firing this event. For instance when shutting down with dirty files. + * + * *Note 2:* Subscribers are called sequentially and they can [delay](#TextDocumentWillSaveEvent.waitUntil) saving + * by registering asynchronous work. Protection against misbehaving listeners is implemented as such: + * * there is an overall time budget that all listeners share and if that is exhausted no further listener is called + * * listeners that take a long time or produce errors frequently will not be called anymore + * + * The current thresholds are 1.5 seconds as overall time budget and a listener can misbehave 3 times before being ignored. + */ + export const onWillSaveTextDocument: Event; + + /** + * An event that is emitted when a [text document](#TextDocument) is saved to disk. + */ + export const onDidSaveTextDocument: Event; + + /** + * An event that is emitted when files are being created. + * + * *Note 1:* This event is triggered by user gestures, like creating a file from the + * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api. This event is *not* fired when + * files change on disk, e.g triggered by another application, or when using the + * [`workspace.fs`](#FileSystem)-api. + * + * *Note 2:* When this event is fired, edits to files that are are being created cannot be applied. + */ + export const onWillCreateFiles: Event; + + /** + * An event that is emitted when files have been created. + * + * *Note:* This event is triggered by user gestures, like creating a file from the + * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * files change on disk, e.g triggered by another application, or when using the + * [`workspace.fs`](#FileSystem)-api. + */ + export const onDidCreateFiles: Event; + + /** + * An event that is emitted when files are being deleted. + * + * *Note 1:* This event is triggered by user gestures, like deleting a file from the + * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * files change on disk, e.g triggered by another application, or when using the + * [`workspace.fs`](#FileSystem)-api. + * + * *Note 2:* When deleting a folder with children only one event is fired. + */ + export const onWillDeleteFiles: Event; + + /** + * An event that is emitted when files have been deleted. + * + * *Note 1:* This event is triggered by user gestures, like deleting a file from the + * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * files change on disk, e.g triggered by another application, or when using the + * [`workspace.fs`](#FileSystem)-api. + * + * *Note 2:* When deleting a folder with children only one event is fired. + */ + export const onDidDeleteFiles: Event; + + /** + * An event that is emitted when files are being renamed. + * + * *Note 1:* This event is triggered by user gestures, like renaming a file from the + * explorer, and from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * files change on disk, e.g triggered by another application, or when using the + * [`workspace.fs`](#FileSystem)-api. + * + * *Note 2:* When renaming a folder with children only one event is fired. + */ + export const onWillRenameFiles: Event; + + /** + * An event that is emitted when files have been renamed. + * + * *Note 1:* This event is triggered by user gestures, like renaming a file from the + * explorer, and from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * files change on disk, e.g triggered by another application, or when using the + * [`workspace.fs`](#FileSystem)-api. + * + * *Note 2:* When renaming a folder with children only one event is fired. + */ + export const onDidRenameFiles: Event; + + /** + * Get a workspace configuration object. + * + * When a section-identifier is provided only that part of the configuration + * is returned. Dots in the section-identifier are interpreted as child-access, + * like `{ myExt: { setting: { doIt: true }}}` and `getConfiguration('myExt.setting').get('doIt') === true`. + * + * When a scope is provided configuration confined to that scope is returned. Scope can be a resource or a language identifier or both. + * + * @param section A dot-separated identifier. + * @param scope A scope for which the configuration is asked for. + * @return The full configuration or a subset. + */ + export function getConfiguration(section?: string | undefined, scope?: ConfigurationScope | null): WorkspaceConfiguration; + + /** + * An event that is emitted when the [configuration](#WorkspaceConfiguration) changed. + */ + export const onDidChangeConfiguration: Event; + + /** + * ~~Register a task provider.~~ + * + * @deprecated Use the corresponding function on the `tasks` namespace instead + * + * @param type The task kind type this provider is registered for. + * @param provider A task provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTaskProvider(type: string, provider: TaskProvider): Disposable; + + /** + * Register a filesystem provider for a given scheme, e.g. `ftp`. + * + * There can only be one provider per scheme and an error is being thrown when a scheme + * has been claimed by another provider or when it is reserved. + * + * @param scheme The uri-[scheme](#Uri.scheme) the provider registers for. + * @param provider The filesystem provider. + * @param options Immutable metadata about the provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerFileSystemProvider(scheme: string, provider: FileSystemProvider, options?: { readonly isCaseSensitive?: boolean, readonly isReadonly?: boolean }): Disposable; + } + + /** + * The configuration scope which can be a + * a 'resource' or a languageId or both or + * a '[TextDocument](#TextDocument)' or + * a '[WorkspaceFolder](#WorkspaceFolder)' + */ + export type ConfigurationScope = Uri | TextDocument | WorkspaceFolder | { uri?: Uri, languageId: string }; + + /** + * An event describing the change in Configuration + */ + export interface ConfigurationChangeEvent { + + /** + * Checks if the given section has changed. + * If scope is provided, checks if the section has changed for resources under the given scope. + * + * @param section Configuration name, supports _dotted_ names. + * @param scope A scope in which to check. + * @return `true` if the given section has changed. + */ + affectsConfiguration(section: string, scope?: ConfigurationScope): boolean; + } + + /** + * Namespace for participating in language-specific editor [features](https://code.visualstudio.com/docs/editor/editingevolved), + * like IntelliSense, code actions, diagnostics etc. + * + * Many programming languages exist and there is huge variety in syntaxes, semantics, and paradigms. Despite that, features + * like automatic word-completion, code navigation, or code checking have become popular across different tools for different + * programming languages. + * + * The editor provides an API that makes it simple to provide such common features by having all UI and actions already in place and + * by allowing you to participate by providing data only. For instance, to contribute a hover all you have to do is provide a function + * that can be called with a [TextDocument](#TextDocument) and a [Position](#Position) returning hover info. The rest, like tracking the + * mouse, positioning the hover, keeping the hover stable etc. is taken care of by the editor. + * + * ```javascript + * languages.registerHoverProvider('javascript', { + * provideHover(document, position, token) { + * return new Hover('I am a hover!'); + * } + * }); + * ``` + * + * Registration is done using a [document selector](#DocumentSelector) which is either a language id, like `javascript` or + * a more complex [filter](#DocumentFilter) like `{ language: 'typescript', scheme: 'file' }`. Matching a document against such + * a selector will result in a [score](#languages.match) that is used to determine if and how a provider shall be used. When + * scores are equal the provider that came last wins. For features that allow full arity, like [hover](#languages.registerHoverProvider), + * the score is only checked to be `>0`, for other features, like [IntelliSense](#languages.registerCompletionItemProvider) the + * score is used for determining the order in which providers are asked to participate. + */ + export namespace languages { + + /** + * Return the identifiers of all known languages. + * @return Promise resolving to an array of identifier strings. + */ + export function getLanguages(): Thenable; + + /** + * Set (and change) the [language](#TextDocument.languageId) that is associated + * with the given document. + * + * *Note* that calling this function will trigger the [`onDidCloseTextDocument`](#workspace.onDidCloseTextDocument) event + * followed by the [`onDidOpenTextDocument`](#workspace.onDidOpenTextDocument) event. + * + * @param document The document which language is to be changed + * @param languageId The new language identifier. + * @returns A thenable that resolves with the updated document. + */ + export function setTextDocumentLanguage(document: TextDocument, languageId: string): Thenable; + + /** + * Compute the match between a document [selector](#DocumentSelector) and a document. Values + * greater than zero mean the selector matches the document. + * + * A match is computed according to these rules: + * 1. When [`DocumentSelector`](#DocumentSelector) is an array, compute the match for each contained `DocumentFilter` or language identifier and take the maximum value. + * 2. A string will be desugared to become the `language`-part of a [`DocumentFilter`](#DocumentFilter), so `"fooLang"` is like `{ language: "fooLang" }`. + * 3. A [`DocumentFilter`](#DocumentFilter) will be matched against the document by comparing its parts with the document. The following rules apply: + * 1. When the `DocumentFilter` is empty (`{}`) the result is `0` + * 2. When `scheme`, `language`, or `pattern` are defined but one doesn’t match, the result is `0` + * 3. Matching against `*` gives a score of `5`, matching via equality or via a glob-pattern gives a score of `10` + * 4. The result is the maximum value of each match + * + * Samples: + * ```js + * // default document from disk (file-scheme) + * doc.uri; //'file:///my/file.js' + * doc.languageId; // 'javascript' + * match('javascript', doc); // 10; + * match({language: 'javascript'}, doc); // 10; + * match({language: 'javascript', scheme: 'file'}, doc); // 10; + * match('*', doc); // 5 + * match('fooLang', doc); // 0 + * match(['fooLang', '*'], doc); // 5 + * + * // virtual document, e.g. from git-index + * doc.uri; // 'git:/my/file.js' + * doc.languageId; // 'javascript' + * match('javascript', doc); // 10; + * match({language: 'javascript', scheme: 'git'}, doc); // 10; + * match('*', doc); // 5 + * ``` + * + * @param selector A document selector. + * @param document A text document. + * @return A number `>0` when the selector matches and `0` when the selector does not match. + */ + export function match(selector: DocumentSelector, document: TextDocument): number; + + /** + * An [event](#Event) which fires when the global set of diagnostics changes. This is + * newly added and removed diagnostics. + */ + export const onDidChangeDiagnostics: Event; + + /** + * Get all diagnostics for a given resource. + * + * @param resource A resource + * @returns An array of [diagnostics](#Diagnostic) objects or an empty array. + */ + export function getDiagnostics(resource: Uri): Diagnostic[]; + + /** + * Get all diagnostics. + * + * @returns An array of uri-diagnostics tuples or an empty array. + */ + export function getDiagnostics(): [Uri, Diagnostic[]][]; + + /** + * Create a diagnostics collection. + * + * @param name The [name](#DiagnosticCollection.name) of the collection. + * @return A new diagnostic collection. + */ + export function createDiagnosticCollection(name?: string): DiagnosticCollection; + + /** + * Register a completion provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and groups of equal score are sequentially asked for + * completion items. The process stops when one or many providers of a group return a + * result. A failing provider (rejected promise or exception) will not fail the whole + * operation. + * + * A completion item provider can be associated with a set of `triggerCharacters`. When trigger + * characters are being typed, completions are requested but only from providers that registered + * the typed character. Because of that trigger characters should be different than [word characters](#LanguageConfiguration.wordPattern), + * a common trigger character is `.` to trigger member completions. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A completion provider. + * @param triggerCharacters Trigger completion when the user types one of the characters. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCompletionItemProvider(selector: DocumentSelector, provider: CompletionItemProvider, ...triggerCharacters: string[]): Disposable; + + /** + * Register a code action provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A code action provider. + * @param metadata Metadata about the kind of code actions the provider provides. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCodeActionsProvider(selector: DocumentSelector, provider: CodeActionProvider, metadata?: CodeActionProviderMetadata): Disposable; + + /** + * Register a code lens provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A code lens provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider): Disposable; + + /** + * Register a definition provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A definition provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDefinitionProvider(selector: DocumentSelector, provider: DefinitionProvider): Disposable; + + /** + * Register an implementation provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An implementation provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerImplementationProvider(selector: DocumentSelector, provider: ImplementationProvider): Disposable; + + /** + * Register a type definition provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A type definition provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTypeDefinitionProvider(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable; + + /** + * Register a declaration provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A declaration provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDeclarationProvider(selector: DocumentSelector, provider: DeclarationProvider): Disposable; + + /** + * Register a hover provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A hover provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Disposable; + + /** + * Register a provider that locates evaluatable expressions in text documents. + * VS Code will evaluate the expression in the active debug session and will show the result in the debug hover. + * + * If multiple providers are registered for a language an arbitrary provider will be used. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An evaluatable expression provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerEvaluatableExpressionProvider(selector: DocumentSelector, provider: EvaluatableExpressionProvider): Disposable; + + /** + * Register a document highlight provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and groups sequentially asked for document highlights. + * The process stops when a provider returns a `non-falsy` or `non-failure` result. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document highlight provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentHighlightProvider(selector: DocumentSelector, provider: DocumentHighlightProvider): Disposable; + + /** + * Register a document symbol provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document symbol provider. + * @param metaData metadata about the provider + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentSymbolProvider(selector: DocumentSelector, provider: DocumentSymbolProvider, metaData?: DocumentSymbolProviderMetadata): Disposable; + + /** + * Register a workspace symbol provider. + * + * Multiple providers can be registered. In that case providers are asked in parallel and + * the results are merged. A failing provider (rejected promise or exception) will not cause + * a failure of the whole operation. + * + * @param provider A workspace symbol provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerWorkspaceSymbolProvider(provider: WorkspaceSymbolProvider): Disposable; + + /** + * Register a reference provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A reference provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerReferenceProvider(selector: DocumentSelector, provider: ReferenceProvider): Disposable; + + /** + * Register a rename provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and asked in sequence. The first provider producing a result + * defines the result of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A rename provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerRenameProvider(selector: DocumentSelector, provider: RenameProvider): Disposable; + + /** + * Register a semantic tokens provider for a whole document. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document semantic tokens provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentSemanticTokensProvider(selector: DocumentSelector, provider: DocumentSemanticTokensProvider, legend: SemanticTokensLegend): Disposable; + + /** + * Register a semantic tokens provider for a document range. + * + * *Note:* If a document has both a `DocumentSemanticTokensProvider` and a `DocumentRangeSemanticTokensProvider`, + * the range provider will be invoked only initially, for the time in which the full document provider takes + * to resolve the first request. Once the full document provider resolves the first request, the semantic tokens + * provided via the range provider will be discarded and from that point forward, only the document provider + * will be used. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document range semantic tokens provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentRangeSemanticTokensProvider(selector: DocumentSelector, provider: DocumentRangeSemanticTokensProvider, legend: SemanticTokensLegend): Disposable; + + /** + * Register a formatting provider for a document. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document formatting edit provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentFormattingEditProvider(selector: DocumentSelector, provider: DocumentFormattingEditProvider): Disposable; + + /** + * Register a formatting provider for a document range. + * + * *Note:* A document range provider is also a [document formatter](#DocumentFormattingEditProvider) + * which means there is no need to [register](#languages.registerDocumentFormattingEditProvider) a document + * formatter when also registering a range provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document range formatting edit provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentRangeFormattingEditProvider(selector: DocumentSelector, provider: DocumentRangeFormattingEditProvider): Disposable; + + /** + * Register a formatting provider that works on type. The provider is active when the user enables the setting `editor.formatOnType`. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An on type formatting edit provider. + * @param firstTriggerCharacter A character on which formatting should be triggered, like `}`. + * @param moreTriggerCharacter More trigger characters. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerOnTypeFormattingEditProvider(selector: DocumentSelector, provider: OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacter: string[]): Disposable; + + /** + * Register a signature help provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and called sequentially until a provider returns a + * valid result. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A signature help provider. + * @param triggerCharacters Trigger signature help when the user types one of the characters, like `,` or `(`. + * @param metadata Information about the provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerSignatureHelpProvider(selector: DocumentSelector, provider: SignatureHelpProvider, ...triggerCharacters: string[]): Disposable; + export function registerSignatureHelpProvider(selector: DocumentSelector, provider: SignatureHelpProvider, metadata: SignatureHelpProviderMetadata): Disposable; + + /** + * Register a document link provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document link provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentLinkProvider(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable; + + /** + * Register a color provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A color provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; + + /** + * Register a folding range provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. + * If multiple folding ranges start at the same position, only the range of the first registered provider is used. + * If a folding range overlaps with an other range that has a smaller position, it is also ignored. + * + * A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A folding range provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerFoldingRangeProvider(selector: DocumentSelector, provider: FoldingRangeProvider): Disposable; + + /** + * Register a selection range provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A selection range provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerSelectionRangeProvider(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable; + + /** + * Register a call hierarchy provider. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A call hierarchy provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable; + + /** + * Set a [language configuration](#LanguageConfiguration) for a language. + * + * @param language A language identifier like `typescript`. + * @param configuration Language configuration. + * @return A [disposable](#Disposable) that unsets this configuration. + */ + export function setLanguageConfiguration(language: string, configuration: LanguageConfiguration): Disposable; + } + + /** + * Represents the input box in the Source Control viewlet. + */ + export interface SourceControlInputBox { + + /** + * Setter and getter for the contents of the input box. + */ + value: string; + + /** + * A string to show as placeholder in the input box to guide the user. + */ + placeholder: string; + + /** + * Controls whether the input box is visible (default is `true`). + */ + visible: boolean; + } + + interface QuickDiffProvider { + + /** + * Provide a [uri](#Uri) to the original resource of any given resource uri. + * + * @param uri The uri of the resource open in a text editor. + * @param token A cancellation token. + * @return A thenable that resolves to uri of the matching original resource. + */ + provideOriginalResource?(uri: Uri, token: CancellationToken): ProviderResult; + } + + /** + * The theme-aware decorations for a + * [source control resource state](#SourceControlResourceState). + */ + export interface SourceControlResourceThemableDecorations { + + /** + * The icon path for a specific + * [source control resource state](#SourceControlResourceState). + */ + readonly iconPath?: string | Uri; + } + + /** + * The decorations for a [source control resource state](#SourceControlResourceState). + * Can be independently specified for light and dark themes. + */ + export interface SourceControlResourceDecorations extends SourceControlResourceThemableDecorations { + + /** + * Whether the [source control resource state](#SourceControlResourceState) should + * be striked-through in the UI. + */ + readonly strikeThrough?: boolean; + + /** + * Whether the [source control resource state](#SourceControlResourceState) should + * be faded in the UI. + */ + readonly faded?: boolean; + + /** + * The title for a specific + * [source control resource state](#SourceControlResourceState). + */ + readonly tooltip?: string; + + /** + * The light theme decorations. + */ + readonly light?: SourceControlResourceThemableDecorations; + + /** + * The dark theme decorations. + */ + readonly dark?: SourceControlResourceThemableDecorations; + } + + /** + * An source control resource state represents the state of an underlying workspace + * resource within a certain [source control group](#SourceControlResourceGroup). + */ + export interface SourceControlResourceState { + + /** + * The [uri](#Uri) of the underlying resource inside the workspace. + */ + readonly resourceUri: Uri; + + /** + * The [command](#Command) which should be run when the resource + * state is open in the Source Control viewlet. + */ + readonly command?: Command; + + /** + * The [decorations](#SourceControlResourceDecorations) for this source control + * resource state. + */ + readonly decorations?: SourceControlResourceDecorations; + } + + /** + * A source control resource group is a collection of + * [source control resource states](#SourceControlResourceState). + */ + export interface SourceControlResourceGroup { + + /** + * The id of this source control resource group. + */ + readonly id: string; + + /** + * The label of this source control resource group. + */ + label: string; + + /** + * Whether this source control resource group is hidden when it contains + * no [source control resource states](#SourceControlResourceState). + */ + hideWhenEmpty?: boolean; + + /** + * This group's collection of + * [source control resource states](#SourceControlResourceState). + */ + resourceStates: SourceControlResourceState[]; + + /** + * Dispose this source control resource group. + */ + dispose(): void; + } + + /** + * An source control is able to provide [resource states](#SourceControlResourceState) + * to the editor and interact with the editor in several source control related ways. + */ + export interface SourceControl { + + /** + * The id of this source control. + */ + readonly id: string; + + /** + * The human-readable label of this source control. + */ + readonly label: string; + + /** + * The (optional) Uri of the root of this source control. + */ + readonly rootUri: Uri | undefined; + + /** + * The [input box](#SourceControlInputBox) for this source control. + */ + readonly inputBox: SourceControlInputBox; + + /** + * The UI-visible count of [resource states](#SourceControlResourceState) of + * this source control. + * + * Equals to the total number of [resource state](#SourceControlResourceState) + * of this source control, if undefined. + */ + count?: number; + + /** + * An optional [quick diff provider](#QuickDiffProvider). + */ + quickDiffProvider?: QuickDiffProvider; + + /** + * Optional commit template string. + * + * The Source Control viewlet will populate the Source Control + * input with this value when appropriate. + */ + commitTemplate?: string; + + /** + * Optional accept input command. + * + * This command will be invoked when the user accepts the value + * in the Source Control input. + */ + acceptInputCommand?: Command; + + /** + * Optional status bar commands. + * + * These commands will be displayed in the editor's status bar. + */ + statusBarCommands?: Command[]; + + /** + * Create a new [resource group](#SourceControlResourceGroup). + */ + createResourceGroup(id: string, label: string): SourceControlResourceGroup; + + /** + * Dispose this source control. + */ + dispose(): void; + } + + export namespace scm { + + /** + * ~~The [input box](#SourceControlInputBox) for the last source control + * created by the extension.~~ + * + * @deprecated Use SourceControl.inputBox instead + */ + export const inputBox: SourceControlInputBox; + + /** + * Creates a new [source control](#SourceControl) instance. + * + * @param id An `id` for the source control. Something short, e.g.: `git`. + * @param label A human-readable string for the source control. E.g.: `Git`. + * @param rootUri An optional Uri of the root of the source control. E.g.: `Uri.parse(workspaceRoot)`. + * @return An instance of [source control](#SourceControl). + */ + export function createSourceControl(id: string, label: string, rootUri?: Uri): SourceControl; + } + + /** + * Configuration for a debug session. + */ + export interface DebugConfiguration { + /** + * The type of the debug session. + */ + type: string; + + /** + * The name of the debug session. + */ + name: string; + + /** + * The request type of the debug session. + */ + request: string; + + /** + * Additional debug type specific properties. + */ + [key: string]: any; + } + + /** + * A debug session. + */ + export interface DebugSession { + + /** + * The unique ID of this debug session. + */ + readonly id: string; + + /** + * The debug session's type from the [debug configuration](#DebugConfiguration). + */ + readonly type: string; + + /** + * The debug session's name is initially taken from the [debug configuration](#DebugConfiguration). + * Any changes will be properly reflected in the UI. + */ + name: string; + + /** + * The workspace folder of this session or `undefined` for a folderless setup. + */ + readonly workspaceFolder: WorkspaceFolder | undefined; + + /** + * The "resolved" [debug configuration](#DebugConfiguration) of this session. + * "Resolved" means that + * - all variables have been substituted and + * - platform specific attribute sections have been "flattened" for the matching platform and removed for non-matching platforms. + */ + readonly configuration: DebugConfiguration; + + /** + * Send a custom request to the debug adapter. + */ + customRequest(command: string, args?: any): Thenable; + } + + /** + * A custom Debug Adapter Protocol event received from a [debug session](#DebugSession). + */ + export interface DebugSessionCustomEvent { + /** + * The [debug session](#DebugSession) for which the custom event was received. + */ + readonly session: DebugSession; + + /** + * Type of event. + */ + readonly event: string; + + /** + * Event specific information. + */ + readonly body?: any; + } + + /** + * A debug configuration provider allows to add debug configurations to the debug service + * and to resolve launch configurations before they are used to start a debug session. + * A debug configuration provider is registered via #debug.registerDebugConfigurationProvider. + */ + export interface DebugConfigurationProvider { + /** + * Provides [debug configuration](#DebugConfiguration) to the debug service. If more than one debug configuration provider is + * registered for the same type, debug configurations are concatenated in arbitrary order. + * + * @param folder The workspace folder for which the configurations are used or `undefined` for a folderless setup. + * @param token A cancellation token. + * @return An array of [debug configurations](#DebugConfiguration). + */ + provideDebugConfigurations?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult; + + /** + * Resolves a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes. + * If more than one debug configuration provider is registered for the same type, the resolveDebugConfiguration calls are chained + * in arbitrary order and the initial debug configuration is piped through the chain. + * Returning the value 'undefined' prevents the debug session from starting. + * Returning the value 'null' prevents the debug session from starting and opens the underlying debug configuration instead. + * + * @param folder The workspace folder from which the configuration originates from or `undefined` for a folderless setup. + * @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve. + * @param token A cancellation token. + * @return The resolved debug configuration or undefined or null. + */ + resolveDebugConfiguration?(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult; + + /** + * This hook is directly called after 'resolveDebugConfiguration' but with all variables substituted. + * It can be used to resolve or verify a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes. + * If more than one debug configuration provider is registered for the same type, the 'resolveDebugConfigurationWithSubstitutedVariables' calls are chained + * in arbitrary order and the initial debug configuration is piped through the chain. + * Returning the value 'undefined' prevents the debug session from starting. + * Returning the value 'null' prevents the debug session from starting and opens the underlying debug configuration instead. + * + * @param folder The workspace folder from which the configuration originates from or `undefined` for a folderless setup. + * @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve. + * @param token A cancellation token. + * @return The resolved debug configuration or undefined or null. + */ + resolveDebugConfigurationWithSubstitutedVariables?(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult; + } + + /** + * Represents a debug adapter executable and optional arguments and runtime options passed to it. + */ + export class DebugAdapterExecutable { + + /** + * Creates a description for a debug adapter based on an executable program. + * + * @param command The command or executable path that implements the debug adapter. + * @param args Optional arguments to be passed to the command or executable. + * @param options Optional options to be used when starting the command or executable. + */ + constructor(command: string, args?: string[], options?: DebugAdapterExecutableOptions); + + /** + * The command or path of the debug adapter executable. + * A command must be either an absolute path of an executable or the name of an command to be looked up via the PATH environment variable. + * The special value 'node' will be mapped to VS Code's built-in Node.js runtime. + */ + readonly command: string; + + /** + * The arguments passed to the debug adapter executable. Defaults to an empty array. + */ + readonly args: string[]; + + /** + * Optional options to be used when the debug adapter is started. + * Defaults to undefined. + */ + readonly options?: DebugAdapterExecutableOptions; + } + + /** + * Options for a debug adapter executable. + */ + export interface DebugAdapterExecutableOptions { + + /** + * The additional environment of the executed program or shell. If omitted + * the parent process' environment is used. If provided it is merged with + * the parent process' environment. + */ + env?: { [key: string]: string }; + + /** + * The current working directory for the executed debug adapter. + */ + cwd?: string; + } + + /** + * Represents a debug adapter running as a socket based server. + */ + export class DebugAdapterServer { + + /** + * The port. + */ + readonly port: number; + + /** + * The host. + */ + readonly host?: string; + + /** + * Create a description for a debug adapter running as a socket based server. + */ + constructor(port: number, host?: string); + } + + /** + * A debug adapter that implements the Debug Adapter Protocol can be registered with VS Code if it implements the DebugAdapter interface. + */ + export interface DebugAdapter extends Disposable { + + /** + * An event which fires after the debug adapter has sent a Debug Adapter Protocol message to VS Code. + * Messages can be requests, responses, or events. + */ + readonly onDidSendMessage: Event; + + /** + * Handle a Debug Adapter Protocol message. + * Messages can be requests, responses, or events. + * Results or errors are returned via onSendMessage events. + * @param message A Debug Adapter Protocol message + */ + handleMessage(message: DebugProtocolMessage): void; + } + + /** + * A DebugProtocolMessage is an opaque stand-in type for the [ProtocolMessage](https://microsoft.github.io/debug-adapter-protocol/specification#Base_Protocol_ProtocolMessage) type defined in the Debug Adapter Protocol. + */ + export interface DebugProtocolMessage { + // Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Base_Protocol_ProtocolMessage). + } + + /** + * A debug adapter descriptor for an inline implementation. + */ + export class DebugAdapterInlineImplementation { + + /** + * Create a descriptor for an inline implementation of a debug adapter. + */ + constructor(implementation: DebugAdapter); + } + + export type DebugAdapterDescriptor = DebugAdapterExecutable | DebugAdapterServer | DebugAdapterInlineImplementation; + + export interface DebugAdapterDescriptorFactory { + /** + * 'createDebugAdapterDescriptor' is called at the start of a debug session to provide details about the debug adapter to use. + * These details must be returned as objects of type [DebugAdapterDescriptor](#DebugAdapterDescriptor). + * Currently two types of debug adapters are supported: + * - a debug adapter executable is specified as a command path and arguments (see [DebugAdapterExecutable](#DebugAdapterExecutable)), + * - a debug adapter server reachable via a communication port (see [DebugAdapterServer](#DebugAdapterServer)). + * If the method is not implemented the default behavior is this: + * createDebugAdapter(session: DebugSession, executable: DebugAdapterExecutable) { + * if (typeof session.configuration.debugServer === 'number') { + * return new DebugAdapterServer(session.configuration.debugServer); + * } + * return executable; + * } + * @param session The [debug session](#DebugSession) for which the debug adapter will be used. + * @param executable The debug adapter's executable information as specified in the package.json (or undefined if no such information exists). + * @return a [debug adapter descriptor](#DebugAdapterDescriptor) or undefined. + */ + createDebugAdapterDescriptor(session: DebugSession, executable: DebugAdapterExecutable | undefined): ProviderResult; + } + + /** + * A Debug Adapter Tracker is a means to track the communication between VS Code and a Debug Adapter. + */ + export interface DebugAdapterTracker { + /** + * A session with the debug adapter is about to be started. + */ + onWillStartSession?(): void; + /** + * The debug adapter is about to receive a Debug Adapter Protocol message from VS Code. + */ + onWillReceiveMessage?(message: any): void; + /** + * The debug adapter has sent a Debug Adapter Protocol message to VS Code. + */ + onDidSendMessage?(message: any): void; + /** + * The debug adapter session is about to be stopped. + */ + onWillStopSession?(): void; + /** + * An error with the debug adapter has occurred. + */ + onError?(error: Error): void; + /** + * The debug adapter has exited with the given exit code or signal. + */ + onExit?(code: number | undefined, signal: string | undefined): void; + } + + export interface DebugAdapterTrackerFactory { + /** + * The method 'createDebugAdapterTracker' is called at the start of a debug session in order + * to return a "tracker" object that provides read-access to the communication between VS Code and a debug adapter. + * + * @param session The [debug session](#DebugSession) for which the debug adapter tracker will be used. + * @return A [debug adapter tracker](#DebugAdapterTracker) or undefined. + */ + createDebugAdapterTracker(session: DebugSession): ProviderResult; + } + + /** + * Represents the debug console. + */ + export interface DebugConsole { + /** + * Append the given value to the debug console. + * + * @param value A string, falsy values will not be printed. + */ + append(value: string): void; + + /** + * Append the given value and a line feed character + * to the debug console. + * + * @param value A string, falsy values will be printed. + */ + appendLine(value: string): void; + } + + /** + * An event describing the changes to the set of [breakpoints](#Breakpoint). + */ + export interface BreakpointsChangeEvent { + /** + * Added breakpoints. + */ + readonly added: ReadonlyArray; + + /** + * Removed breakpoints. + */ + readonly removed: ReadonlyArray; + + /** + * Changed breakpoints. + */ + readonly changed: ReadonlyArray; + } + + /** + * The base class of all breakpoint types. + */ + export class Breakpoint { + /** + * The unique ID of the breakpoint. + */ + readonly id: string; + /** + * Is breakpoint enabled. + */ + readonly enabled: boolean; + /** + * An optional expression for conditional breakpoints. + */ + readonly condition?: string; + /** + * An optional expression that controls how many hits of the breakpoint are ignored. + */ + readonly hitCondition?: string; + /** + * An optional message that gets logged when this breakpoint is hit. Embedded expressions within {} are interpolated by the debug adapter. + */ + readonly logMessage?: string; + + protected constructor(enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); + } + + /** + * A breakpoint specified by a source location. + */ + export class SourceBreakpoint extends Breakpoint { + /** + * The source and line position of this breakpoint. + */ + readonly location: Location; + + /** + * Create a new breakpoint for a source location. + */ + constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); + } + + /** + * A breakpoint specified by a function name. + */ + export class FunctionBreakpoint extends Breakpoint { + /** + * The name of the function to which this breakpoint is attached. + */ + readonly functionName: string; + + /** + * Create a new function breakpoint. + */ + constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); + } + + /** + * Debug console mode used by debug session, see [options](#DebugSessionOptions). + */ + export enum DebugConsoleMode { + /** + * Debug session should have a separate debug console. + */ + Separate = 0, + + /** + * Debug session should share debug console with its parent session. + * This value has no effect for sessions which do not have a parent session. + */ + MergeWithParent = 1 + } + + /** + * Options for [starting a debug session](#debug.startDebugging). + */ + export interface DebugSessionOptions { + + /** + * When specified the newly created debug session is registered as a "child" session of this + * "parent" debug session. + */ + parentSession?: DebugSession; + + /** + * Controls whether this session should have a separate debug console or share it + * with the parent session. Has no effect for sessions which do not have a parent session. + * Defaults to Separate. + */ + consoleMode?: DebugConsoleMode; + } + + /** + * A DebugProtocolSource is an opaque stand-in type for the [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) type defined in the Debug Adapter Protocol. + */ + export interface DebugProtocolSource { + // Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source). + } + + /** + * A DebugConfigurationProviderTriggerKind specifies when the `provideDebugConfigurations` method of a `DebugConfigurationProvider` is triggered. + * Currently there are two situations: to provide the initial debug configurations for a newly created launch.json or + * to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command). + * A trigger kind is used when registering a `DebugConfigurationProvider` with #debug.registerDebugConfigurationProvider. + */ + export enum DebugConfigurationProviderTriggerKind { + /** + * `DebugConfigurationProvider.provideDebugConfigurations` is called to provide the initial debug configurations for a newly created launch.json. + */ + Initial = 1, + /** + * `DebugConfigurationProvider.provideDebugConfigurations` is called to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command). + */ + Dynamic = 2 + } + + /** + * Namespace for debug functionality. + */ + export namespace debug { + + /** + * The currently active [debug session](#DebugSession) or `undefined`. The active debug session is the one + * represented by the debug action floating window or the one currently shown in the drop down menu of the debug action floating window. + * If no debug session is active, the value is `undefined`. + */ + export let activeDebugSession: DebugSession | undefined; + + /** + * The currently active [debug console](#DebugConsole). + * If no debug session is active, output sent to the debug console is not shown. + */ + export let activeDebugConsole: DebugConsole; + + /** + * List of breakpoints. + */ + export let breakpoints: Breakpoint[]; + + /** + * An [event](#Event) which fires when the [active debug session](#debug.activeDebugSession) + * has changed. *Note* that the event also fires when the active debug session changes + * to `undefined`. + */ + export const onDidChangeActiveDebugSession: Event; + + /** + * An [event](#Event) which fires when a new [debug session](#DebugSession) has been started. + */ + export const onDidStartDebugSession: Event; + + /** + * An [event](#Event) which fires when a custom DAP event is received from the [debug session](#DebugSession). + */ + export const onDidReceiveDebugSessionCustomEvent: Event; + + /** + * An [event](#Event) which fires when a [debug session](#DebugSession) has terminated. + */ + export const onDidTerminateDebugSession: Event; + + /** + * An [event](#Event) that is emitted when the set of breakpoints is added, removed, or changed. + */ + export const onDidChangeBreakpoints: Event; + + /** + * Register a [debug configuration provider](#DebugConfigurationProvider) for a specific debug type. + * The optional [triggerKind](#DebugConfigurationProviderTriggerKind) can be used to specify when the `provideDebugConfigurations` method of the provider is triggered. + * Currently two trigger kinds are possible: with the value `Initial` (or if no trigger kind argument is given) the `provideDebugConfigurations` method is used to provide the initial debug configurations to be copied into a newly created launch.json. + * With the trigger kind `Dynamic` the `provideDebugConfigurations` method is used to dynamically determine debug configurations to be presented to the user (in addition to the static configurations from the launch.json). + * Please note that the `triggerKind` argument only applies to the `provideDebugConfigurations` method: so the `resolveDebugConfiguration` methods are not affected at all. + * Registering a single provider with resolve methods for different trigger kinds, results in the same resolve methods called multiple times. + * More than one provider can be registered for the same type. + * + * @param type The debug type for which the provider is registered. + * @param provider The [debug configuration provider](#DebugConfigurationProvider) to register. + * @param triggerKind The [trigger](#DebugConfigurationProviderTrigger) for which the 'provideDebugConfiguration' method of the provider is registered. If `triggerKind` is missing, the value `DebugConfigurationProviderTriggerKind.Initial` is assumed. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDebugConfigurationProvider(debugType: string, provider: DebugConfigurationProvider, triggerKind?: DebugConfigurationProviderTriggerKind): Disposable; + + /** + * Register a [debug adapter descriptor factory](#DebugAdapterDescriptorFactory) for a specific debug type. + * An extension is only allowed to register a DebugAdapterDescriptorFactory for the debug type(s) defined by the extension. Otherwise an error is thrown. + * Registering more than one DebugAdapterDescriptorFactory for a debug type results in an error. + * + * @param debugType The debug type for which the factory is registered. + * @param factory The [debug adapter descriptor factory](#DebugAdapterDescriptorFactory) to register. + * @return A [disposable](#Disposable) that unregisters this factory when being disposed. + */ + export function registerDebugAdapterDescriptorFactory(debugType: string, factory: DebugAdapterDescriptorFactory): Disposable; + + /** + * Register a debug adapter tracker factory for the given debug type. + * + * @param debugType The debug type for which the factory is registered or '*' for matching all debug types. + * @param factory The [debug adapter tracker factory](#DebugAdapterTrackerFactory) to register. + * @return A [disposable](#Disposable) that unregisters this factory when being disposed. + */ + export function registerDebugAdapterTrackerFactory(debugType: string, factory: DebugAdapterTrackerFactory): Disposable; + + /** + * Start debugging by using either a named launch or named compound configuration, + * or by directly passing a [DebugConfiguration](#DebugConfiguration). + * The named configurations are looked up in '.vscode/launch.json' found in the given folder. + * Before debugging starts, all unsaved files are saved and the launch configurations are brought up-to-date. + * Folder specific variables used in the configuration (e.g. '${workspaceFolder}') are resolved against the given folder. + * @param folder The [workspace folder](#WorkspaceFolder) for looking up named configurations and resolving variables or `undefined` for a non-folder setup. + * @param nameOrConfiguration Either the name of a debug or compound configuration or a [DebugConfiguration](#DebugConfiguration) object. + * @param parentSessionOrOptions Debug session options. When passed a parent [debug session](#DebugSession), assumes options with just this parent session. + * @return A thenable that resolves when debugging could be successfully started. + */ + export function startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSessionOrOptions?: DebugSession | DebugSessionOptions): Thenable; + + /** + * Add breakpoints. + * @param breakpoints The breakpoints to add. + */ + export function addBreakpoints(breakpoints: Breakpoint[]): void; + + /** + * Remove breakpoints. + * @param breakpoints The breakpoints to remove. + */ + export function removeBreakpoints(breakpoints: Breakpoint[]): void; + + /** + * Converts a "Source" descriptor object received via the Debug Adapter Protocol into a Uri that can be used to load its contents. + * If the source descriptor is based on a path, a file Uri is returned. + * If the source descriptor uses a reference number, a specific debug Uri (scheme 'debug') is constructed that requires a corresponding VS Code ContentProvider and a running debug session + * + * If the "Source" descriptor has insufficient information for creating the Uri, an error is thrown. + * + * @param source An object conforming to the [Source](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source) type defined in the Debug Adapter Protocol. + * @param session An optional debug session that will be used when the source descriptor uses a reference number to load the contents from an active debug session. + * @return A uri that can be used to load the contents of the source. + */ + export function asDebugSourceUri(source: DebugProtocolSource, session?: DebugSession): Uri; + } + + /** + * Namespace for dealing with installed extensions. Extensions are represented + * by an [extension](#Extension)-interface which enables reflection on them. + * + * Extension writers can provide APIs to other extensions by returning their API public + * surface from the `activate`-call. + * + * ```javascript + * export function activate(context: vscode.ExtensionContext) { + * let api = { + * sum(a, b) { + * return a + b; + * }, + * mul(a, b) { + * return a * b; + * } + * }; + * // 'export' public api-surface + * return api; + * } + * ``` + * When depending on the API of another extension add an `extensionDependencies`-entry + * to `package.json`, and use the [getExtension](#extensions.getExtension)-function + * and the [exports](#Extension.exports)-property, like below: + * + * ```javascript + * let mathExt = extensions.getExtension('genius.math'); + * let importedApi = mathExt.exports; + * + * console.log(importedApi.mul(42, 1)); + * ``` + */ + export namespace extensions { + + /** + * Get an extension by its full identifier in the form of: `publisher.name`. + * + * @param extensionId An extension identifier. + * @return An extension or `undefined`. + */ + export function getExtension(extensionId: string): Extension | undefined; + + /** + * Get an extension by its full identifier in the form of: `publisher.name`. + * + * @param extensionId An extension identifier. + * @return An extension or `undefined`. + */ + export function getExtension(extensionId: string): Extension | undefined; + + /** + * All extensions currently known to the system. + */ + export const all: ReadonlyArray>; + + /** + * An event which fires when `extensions.all` changes. This can happen when extensions are + * installed, uninstalled, enabled or disabled. + */ + export const onDidChange: Event; + } + + //#region Comments + + /** + * Collapsible state of a [comment thread](#CommentThread) + */ + export enum CommentThreadCollapsibleState { + /** + * Determines an item is collapsed + */ + Collapsed = 0, + + /** + * Determines an item is expanded + */ + Expanded = 1 + } + + /** + * Comment mode of a [comment](#Comment) + */ + export enum CommentMode { + /** + * Displays the comment editor + */ + Editing = 0, + + /** + * Displays the preview of the comment + */ + Preview = 1 + } + + /** + * A collection of [comments](#Comment) representing a conversation at a particular range in a document. + */ + export interface CommentThread { + /** + * The uri of the document the thread has been created on. + */ + readonly uri: Uri; + + /** + * The range the comment thread is located within the document. The thread icon will be shown + * at the first line of the range. + */ + range: Range; + + /** + * The ordered comments of the thread. + */ + comments: ReadonlyArray; + + /** + * Whether the thread should be collapsed or expanded when opening the document. + * Defaults to Collapsed. + */ + collapsibleState: CommentThreadCollapsibleState; + + /** + * Context value of the comment thread. This can be used to contribute thread specific actions. + * For example, a comment thread is given a context value as `editable`. When contributing actions to `comments/commentThread/title` + * using `menus` extension point, you can specify context value for key `commentThread` in `when` expression like `commentThread == editable`. + * ``` + * "contributes": { + * "menus": { + * "comments/commentThread/title": [ + * { + * "command": "extension.deleteCommentThread", + * "when": "commentThread == editable" + * } + * ] + * } + * } + * ``` + * This will show action `extension.deleteCommentThread` only for comment threads with `contextValue` is `editable`. + */ + contextValue?: string; + + /** + * The optional human-readable label describing the [Comment Thread](#CommentThread) + */ + label?: string; + + /** + * Dispose this comment thread. + * + * Once disposed, this comment thread will be removed from visible editors and Comment Panel when appropriate. + */ + dispose(): void; + } + + /** + * Author information of a [comment](#Comment) + */ + export interface CommentAuthorInformation { + /** + * The display name of the author of the comment + */ + name: string; + + /** + * The optional icon path for the author + */ + iconPath?: Uri; + } + + /** + * Reactions of a [comment](#Comment) + */ + export interface CommentReaction { + /** + * The human-readable label for the reaction + */ + readonly label: string; + + /** + * Icon for the reaction shown in UI. + */ + readonly iconPath: string | Uri; + + /** + * The number of users who have reacted to this reaction + */ + readonly count: number; + + /** + * Whether the [author](CommentAuthorInformation) of the comment has reacted to this reaction + */ + readonly authorHasReacted: boolean; + } + + /** + * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. + */ + export interface Comment { + /** + * The human-readable comment body + */ + body: string | MarkdownString; + + /** + * [Comment mode](#CommentMode) of the comment + */ + mode: CommentMode; + + /** + * The [author information](#CommentAuthorInformation) of the comment + */ + author: CommentAuthorInformation; + + /** + * Context value of the comment. This can be used to contribute comment specific actions. + * For example, a comment is given a context value as `editable`. When contributing actions to `comments/comment/title` + * using `menus` extension point, you can specify context value for key `comment` in `when` expression like `comment == editable`. + * ```json + * "contributes": { + * "menus": { + * "comments/comment/title": [ + * { + * "command": "extension.deleteComment", + * "when": "comment == editable" + * } + * ] + * } + * } + * ``` + * This will show action `extension.deleteComment` only for comments with `contextValue` is `editable`. + */ + contextValue?: string; + + /** + * Optional reactions of the [comment](#Comment) + */ + reactions?: CommentReaction[]; + + /** + * Optional label describing the [Comment](#Comment) + * Label will be rendered next to authorName if exists. + */ + label?: string; + } + + /** + * Command argument for actions registered in `comments/commentThread/context`. + */ + export interface CommentReply { + /** + * The active [comment thread](#CommentThread) + */ + thread: CommentThread; + + /** + * The value in the comment editor + */ + text: string; + } + + /** + * Commenting range provider for a [comment controller](#CommentController). + */ + export interface CommentingRangeProvider { + /** + * Provide a list of ranges which allow new comment threads creation or null for a given document + */ + provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult; + } + + /** + * Represents a [comment controller](#CommentController)'s [options](#CommentController.options). + */ + export interface CommentOptions { + /** + * An optional string to show on the comment input box when it's collapsed. + */ + prompt?: string; + + /** + * An optional string to show as placeholder in the comment input box when it's focused. + */ + placeHolder?: string; + } + + /** + * A comment controller is able to provide [comments](#CommentThread) support to the editor and + * provide users various ways to interact with comments. + */ + export interface CommentController { + /** + * The id of this comment controller. + */ + readonly id: string; + + /** + * The human-readable label of this comment controller. + */ + readonly label: string; + + /** + * Comment controller options + */ + options?: CommentOptions; + + /** + * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. + * + * If not provided, users can leave comments in any document opened in the editor. + */ + commentingRangeProvider?: CommentingRangeProvider; + + /** + * Create a [comment thread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) + * and Comments Panel once created. + * + * @param uri The uri of the document the thread has been created on. + * @param range The range the comment thread is located within the document. + * @param comments The ordered comments of the thread. + */ + createCommentThread(uri: Uri, range: Range, comments: Comment[]): CommentThread; + + /** + * Optional reaction handler for creating and deleting reactions on a [comment](#Comment). + */ + reactionHandler?: (comment: Comment, reaction: CommentReaction) => Promise; + + /** + * Dispose this comment controller. + * + * Once disposed, all [comment threads](#CommentThread) created by this comment controller will also be removed from the editor + * and Comments Panel. + */ + dispose(): void; + } + + namespace comments { + /** + * Creates a new [comment controller](#CommentController) instance. + * + * @param id An `id` for the comment controller. + * @param label A human-readable string for the comment controller. + * @return An instance of [comment controller](#CommentController). + */ + export function createCommentController(id: string, label: string): CommentController; + } + + //#endregion + + /** + * Represents a session of a currently logged in user. + */ + export interface AuthenticationSession { + /** + * The identifier of the authentication session. + */ + readonly id: string; + + /** + * The access token. + */ + readonly accessToken: string; + + /** + * The account associated with the session. + */ + readonly account: AuthenticationSessionAccountInformation; + + /** + * The permissions granted by the session's access token. Available scopes + * are defined by the [AuthenticationProvider](#AuthenticationProvider). + */ + readonly scopes: ReadonlyArray; + } + + /** + * The information of an account associated with an [AuthenticationSession](#AuthenticationSession). + */ + export interface AuthenticationSessionAccountInformation { + /** + * The unique identifier of the account. + */ + readonly id: string; + + /** + * The human-readable name of the account. + */ + readonly label: string; + } + + + /** + * Options to be used when getting an [AuthenticationSession](#AuthenticationSession) from an [AuthenticationProvider](#AuthenticationProvider). + */ + export interface AuthenticationGetSessionOptions { + /** + * Whether login should be performed if there is no matching session. + * + * If true, a modal dialog will be shown asking the user to sign in. If false, a numbered badge will be shown + * on the accounts activity bar icon. An entry for the extension will be added under the menu to sign in. This + * allows quietly prompting the user to sign in. + * + * Defaults to false. + */ + createIfNone?: boolean; + + /** + * Whether the existing user session preference should be cleared. + * + * For authentication providers that support being signed into multiple accounts at once, the user will be + * prompted to select an account to use when [getSession](#authentication.getSession) is called. This preference + * is remembered until [getSession](#authentication.getSession) is called with this flag. + * + * Defaults to false. + */ + clearSessionPreference?: boolean; + } + + /** + * Basic information about an [authenticationProvider](#AuthenticationProvider) + */ + export interface AuthenticationProviderInformation { + /** + * The unique identifier of the authentication provider. + */ + readonly id: string; + + /** + * The human-readable name of the authentication provider. + */ + readonly label: string; + } + + /** + * An [event](#Event) which fires when an [AuthenticationSession](#AuthenticationSession) is added, removed, or changed. + */ + export interface AuthenticationSessionsChangeEvent { + /** + * The [authenticationProvider](#AuthenticationProvider) that has had its sessions change. + */ + readonly provider: AuthenticationProviderInformation; + } + + /** + * Namespace for authentication. + */ + export namespace authentication { + /** + * Get an authentication session matching the desired scopes. Rejects if a provider with providerId is not + * registered, or if the user does not consent to sharing authentication information with + * the extension. If there are multiple sessions with the same scopes, the user will be shown a + * quickpick to select which account they would like to use. + * + * Currently, there are only two authentication providers that are contributed from built in extensions + * to VS Code that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'. + * @param providerId The id of the provider to use + * @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider + * @param options The [getSessionOptions](#GetSessionOptions) to use + * @returns A thenable that resolves to an authentication session + */ + export function getSession(providerId: string, scopes: string[], options: AuthenticationGetSessionOptions & { createIfNone: true }): Thenable; + + /** + * Get an authentication session matching the desired scopes. Rejects if a provider with providerId is not + * registered, or if the user does not consent to sharing authentication information with + * the extension. If there are multiple sessions with the same scopes, the user will be shown a + * quickpick to select which account they would like to use. + * + * Currently, there are only two authentication providers that are contributed from built in extensions + * to VS Code that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'. + * @param providerId The id of the provider to use + * @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider + * @param options The [getSessionOptions](#GetSessionOptions) to use + * @returns A thenable that resolves to an authentication session if available, or undefined if there are no sessions + */ + export function getSession(providerId: string, scopes: string[], options?: AuthenticationGetSessionOptions): Thenable; + + /** + * An [event](#Event) which fires when the authentication sessions of an authentication provider have + * been added, removed, or changed. + */ + export const onDidChangeSessions: Event; + } +} + +/** + * Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise, + * and others. This API makes no assumption about what promise library is being used which + * enables reusing existing code without migrating to a specific promise implementation. Still, + * we recommend the use of native promises which are available in this editor. + */ +interface Thenable { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable; + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable; +} diff --git a/honk/editors/vscode/sys/@types/vscode/package.json b/honk/editors/vscode/sys/@types/vscode/package.json new file mode 100644 index 000000000..b2afb3c28 --- /dev/null +++ b/honk/editors/vscode/sys/@types/vscode/package.json @@ -0,0 +1,53 @@ +{ + "_from": "@types/vscode@^1.48.0", + "_id": "@types/vscode@1.48.0", + "_inBundle": false, + "_integrity": "sha512-sZJKzsJz1gSoFXcOJWw3fnKl2sseUgZmvB4AJZS+Fea+bC/jfGPVhmFL/FfQHld/TKtukVONsmoD3Pkyx9iadg==", + "_location": "/@types/vscode", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "@types/vscode@^1.48.0", + "name": "@types/vscode", + "escapedName": "@types%2fvscode", + "scope": "@types", + "rawSpec": "^1.48.0", + "saveSpec": null, + "fetchSpec": "^1.48.0" + }, + "_requiredBy": [ + "#DEV:/" + ], + "_resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.48.0.tgz", + "_shasum": "c1841ccf80086d53b35a9d7f2eb3b4d949bd2d2f", + "_spec": "@types/vscode@^1.48.0", + "_where": "D:\\code\\moxie\\honk\\editors\\vscode\\honk", + "bugs": { + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Visual Studio Code Team, Microsoft", + "url": "https://github.com/Microsoft" + } + ], + "dependencies": {}, + "deprecated": false, + "description": "TypeScript definitions for Visual Studio Code", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped#readme", + "license": "MIT", + "main": "", + "name": "@types/vscode", + "repository": { + "type": "git", + "url": "git+https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/vscode" + }, + "scripts": {}, + "typeScriptVersion": "3.0", + "types": "index.d.ts", + "typesPublisherContentHash": "9ec5712e8a8f2248ce0b94cb917bf09a78e28301913f399a71c003c5612d4b6d", + "version": "1.48.0" +} diff --git a/honk/editors/vscode/sys/Cargo.toml b/honk/editors/vscode/sys/Cargo.toml new file mode 100644 index 000000000..eafc59b51 --- /dev/null +++ b/honk/editors/vscode/sys/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "code-sys" +version = "0.1.0-pre" +description = "Bindings to VSCode's extension API using wasm-bindgen." +categories = [] +keywords = [] +readme = "CHANGELOG.md" + +# update here, update everywhere! +license = "MIT/Apache-2.0" +homepage = "https://moxie.rs" +repository = "https://github.com/anp/moxie.git" +authors = ["Adam Perry "] +edition = "2018" + +[dependencies] +wasm-bindgen = "0.2" + +[build-dependencies] +ts-bindgen = { path = "../../../../dom/ts-bindgen", version = "0.1.0" } \ No newline at end of file diff --git a/honk/editors/vscode/sys/build.rs b/honk/editors/vscode/sys/build.rs new file mode 100644 index 000000000..1b4498f55 --- /dev/null +++ b/honk/editors/vscode/sys/build.rs @@ -0,0 +1,3 @@ +fn main() { + ts_bindgen::d_ts_buildscript("@types/vscode/index.d.ts", "index.d.rs").unwrap(); +} diff --git a/honk/editors/vscode/sys/src/lib.rs b/honk/editors/vscode/sys/src/lib.rs new file mode 100644 index 000000000..f4951bb7a --- /dev/null +++ b/honk/editors/vscode/sys/src/lib.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/index.d.rs")); From ae4e60224adc299c2358e343b1a494d3fa725dc0 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 7 Sep 2020 08:24:49 -0700 Subject: [PATCH 41/41] [honk][vscode] add lib.rs (oops) --- honk/editors/vscode/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 honk/editors/vscode/src/lib.rs diff --git a/honk/editors/vscode/src/lib.rs b/honk/editors/vscode/src/lib.rs new file mode 100644 index 000000000..26ac684d7 --- /dev/null +++ b/honk/editors/vscode/src/lib.rs @@ -0,0 +1,9 @@ +use tracing::*; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen(start)] +pub fn setup_tracing() { + tracing_wasm::set_as_global_default(); + console_error_panic_hook::set_once(); + info!("tracing initialized"); +}