├── .gitattributes ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .prettierignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── images ├── smithy_anvil_red.png └── smithy_anvil_red_file_icon.png ├── info.plist ├── language-configuration.json ├── package-lock.json ├── package.json ├── snippets.json ├── src ├── config.ts ├── coursier │ ├── coursier.ts │ └── download-coursier.ts ├── extension.ts ├── jar-file-contents.ts └── selector.ts ├── syntaxes └── smithy.tmLanguage.json ├── test-fixtures ├── suite1 │ ├── .vscode │ │ └── settings.json │ ├── main.smithy │ └── smithy-build.json ├── suite2 │ ├── main.smithy │ └── smithy-build.json ├── suite3 │ ├── .vscode │ │ └── settings.json │ ├── main.smithy │ └── smithy-build.json ├── suite4 │ ├── .vscode │ │ └── settings.json │ └── smithy │ │ ├── main.smithy │ │ └── smithy-build.json ├── suite5 │ ├── .vscode │ │ └── settings.json │ └── smithy │ │ ├── main.smithy │ │ └── smithy-build.json └── suite6 │ └── smithy-build.json ├── tests ├── grammar │ ├── aggregate-shapes.smithy │ ├── apply.smithy │ ├── control.smithy │ ├── enums.smithy │ ├── metadata.smithy │ ├── mixins.smithy │ ├── namespace.smithy │ ├── service-shapes.smithy │ ├── simple-shapes.smithy │ ├── target-elision.smithy │ ├── traits.smithy │ └── use.smithy ├── helper.ts ├── runTest.ts ├── suite1 │ ├── extension.test.ts │ └── index.ts ├── suite2 │ ├── extension.test.ts │ └── index.ts ├── suite3 │ ├── extension.test.ts │ └── index.ts ├── suite4 │ ├── extension.test.ts │ └── index.ts ├── suite5 │ ├── extension.test.ts │ └── index.ts └── suite6 │ ├── extension.test.ts │ └── index.ts ├── tsconfig.json └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Add core contributors to all prs by default 2 | * @smithy-lang/smithy 3 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | test-extension: 11 | runs-on: ubuntu-latest 12 | name: Test Textmate syntax and extension 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: "18" 19 | 20 | - name: Install dependencies 21 | run: npm install 22 | 23 | - name: Run tests 24 | run: xvfb-run -a npm test 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | build 4 | .coverage/ 5 | .vscode-test/ 6 | *.vsix 7 | **/.DS_Store 8 | .idea 9 | telemetryCache 10 | .smithy.lsp.log 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | out/ 2 | node_modules/ 3 | build/ 4 | .vscode/ 5 | .vscode-test/ 6 | test-fixtures/**/build 7 | package-lock.json 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension - Test Suite 1 - Language Registration", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "preLaunchTask": "compile", 13 | "runtimeExecutable": "${execPath}", 14 | "args": [ 15 | "--disable-extensions", 16 | "--extensionDevelopmentPath=${workspaceRoot}", 17 | "--extensionTestsPath=${workspaceRoot}/out/tests/suite1", 18 | "${workspaceRoot}/test-fixtures/suite1", 19 | ], 20 | "outFiles": ["${workspaceRoot}/out/tests/suite1/*.js"] 21 | }, 22 | { 23 | "name": "Extension - Test Suite 2 - Diagnostics", 24 | "type": "extensionHost", 25 | "request": "launch", 26 | "preLaunchTask": "compile", 27 | "runtimeExecutable": "${execPath}", 28 | "args": [ 29 | "--disable-extensions", 30 | "--extensionDevelopmentPath=${workspaceRoot}", 31 | "--extensionTestsPath=${workspaceRoot}/out/tests/suite2", 32 | "${workspaceRoot}/test-fixtures/suite2", 33 | ], 34 | "outFiles": ["${workspaceRoot}/out/tests/suite2/*.js"] 35 | }, 36 | { 37 | "name": "Extension - Test Suite 3 - Selectors", 38 | "type": "extensionHost", 39 | "request": "launch", 40 | "preLaunchTask": "compile", 41 | "runtimeExecutable": "${execPath}", 42 | "args": [ 43 | "--disable-extensions", 44 | "--extensionDevelopmentPath=${workspaceRoot}", 45 | "--extensionTestsPath=${workspaceRoot}/out/tests/suite3", 46 | "${workspaceRoot}/test-fixtures/suite3", 47 | ], 48 | "outFiles": ["${workspaceRoot}/out/tests/suite3/*.js"] 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "compile", 8 | "command": "npm", 9 | "args": ["run", "compile"] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .github 4 | .gitignore 5 | .prettierignore 6 | .idea 7 | vsc-extension-quickstart.md 8 | node_modules 9 | out/ 10 | !out/src/extension.* 11 | src 12 | test-fixtures 13 | tests 14 | tsconfig.json 15 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/smithy-lang/smithy-vscode/issues), or [recently closed](https://github.com/smithy-lang/smithy-vscode/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/smithy-lang/smithy-vscode/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/smithy-lang/smithy-vscode/blob/main/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Smithy for VS Code 2 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smithy for VS Code 2 | 3 | This package is a Visual Studio Code extension to recognize and highlight the 4 | Smithy interface definition language (IDL). It can also be used as a TextMate 5 | bundle in TextMate and [IntelliJ using a third-party plugin](https://www.jetbrains.com/help/idea/importing-textmate-bundles.html). 6 | 7 | ## Features 8 | 9 | This extension provides basic syntax highlighting of ".smithy" files. 10 | 11 | Additionally, it provides [Snippets](https://code.visualstudio.com/docs/editor/userdefinedsnippets). 12 | 13 | ## Installation 14 | 15 | This extension can be installed from the 16 | [VS Code Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=smithy.smithy-vscode-extension). 17 | 18 | To install from source, follow these steps: 19 | * Clone the repository: `git clone https://github.com/awslabs/smithy-vscode.git && cd smithy-vscode` 20 | * Run npm commands to install: 21 | `npm install && npm run install-plugin` 22 | 23 | ## Authoring a model 24 | If your model requires dependencies, add a `smithy-build.json` file to the root of your project, specifying Maven dependencies, along with the 25 | repositories where they can be located. 26 | ``` 27 | { 28 | "version": "1.0", 29 | "maven": { 30 | "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], 31 | "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] 32 | } 33 | } 34 | ``` 35 | Start authoring your Smithy model. Opening a `*.smithy` file will activate 36 | the extension. 37 | 38 | ## Use with any Maven private registry 39 | 40 | Follow [these instructions](https://get-coursier.io/docs/other-credentials#property-file) to set the credentials file for your Maven private registry. Here is an example for a Maven registry provided by GitHub: 41 | ``` 42 | github.username= 43 | github.password= 44 | github.host=maven.pkg.github.com 45 | ``` 46 | 47 | ## Use with IntelliJ 48 | 49 | You can use this extension for syntax highlighting in IntelliJ by installing the 50 | "TextMate bundle support" plugin and registering this repository as a bundle. 51 | See the [IntelliJ documentation](https://www.jetbrains.com/help/idea/textmate.html) 52 | for more details. 53 | 54 | ## Release Notes 55 | 56 | ### 0.9.0 - 2025-04-16 57 | 58 | - Added setting to run the smithy-language-server using a specific executable [#106](https://github.com/smithy-lang/smithy-vscode/pull/106) 59 | - Changed name of settings to `smithy.*` and deprecated old settings [#106](https://github.com/smithy-lang/smithy-vscode/pull/106) 60 | - Added syntax highlighting for hovering on members [#107](https://github.com/smithy-lang/smithy-vscode/pull/107) 61 | - Updated smithy-language-server version to 0.7.0 [#108](https://github.com/smithy-lang/smithy-vscode/pull/108) 62 | 63 | ### 0.8.0 - 2025-03-10 64 | 65 | - Updated smithy-language-server version to 0.6.0 [#103](https://github.com/smithy-lang/smithy-vscode/pull/103) 66 | - Use language server for smithy-build.json support [#102](https://github.com/smithy-lang/smithy-vscode/pull/102) 67 | 68 | ### 0.7.0 - 2024-11-26 69 | 70 | - Updated smithy-language-server version to 0.5.0 [#97](https://github.com/smithy-lang/smithy-vscode/pull/97) 71 | - Extension now starts when any Smithy files are found in the workspace [#96](https://github.com/smithy-lang/smithy-vscode/pull/96) 72 | 73 | ### 0.6.1 - 2024-09-09 74 | 75 | - Updated smithy-language-server version to 0.4.1 [#94](https://github.com/smithy-lang/smithy-vscode/pull/94) 76 | 77 | ### 0.6.0 - 2024-08-02 78 | 79 | - Updated smithy-language-server version to 0.4.0 [#89](https://github.com/smithy-lang/smithy-vscode/pull/89) 80 | - Removed configuration for .smithy.lsp.log file [#89](https://github.com/smithy-lang/smithy-vscode/pull/89) 81 | - Added configuration option for model validation minimum severity [#89](https://github.com/smithy-lang/smithy-vscode/pull/89) 82 | - Added configuration option for only reloading the model on save [#89](https://github.com/smithy-lang/smithy-vscode/pull/89) 83 | 84 | ### 0.5.4 - 2023-11-09 85 | 86 | - Added configuration for LspLog file. [#82](https://github.com/smithy-lang/smithy-vscode/pull/82) 87 | - Added `smithy-build.json` JSON Schema. [#76](https://github.com/smithy-lang/smithy-vscode/pull/76) 88 | - Fixed grammar for `apply` statement. [#76](https://github.com/smithy-lang/smithy-vscode/pull/75) 89 | 90 | ### 0.5.3 - 2023-03-17 91 | 92 | - Added model formatting via Smithy Language Server 0.2.3. [#67](https://github.com/awslabs/smithy-vscode/pull/67) 93 | 94 | ### 0.5.2 - 2022-12-27 95 | 96 | - Updated to use [Smithy Language Server 0.2.2](https://github.com/awslabs/smithy-language-server/). 97 | 98 | ### 0.5.1 - 2022-09-29 99 | 100 | - Updated to use [Smithy Language Server 0.2.1](https://github.com/awslabs/smithy-language-server/). 101 | - Stopped switching focus to VSCode's output window when the extension receives a message. [#55](https://github.com/awslabs/smithy-vscode/pull/55) 102 | - Allowed setting the root path to be used by the extension. [#54](https://github.com/awslabs/smithy-vscode/pull/54) 103 | - Updated tests to use version 1.25.0 for Smithy packages. [#56](https://github.com/awslabs/smithy-vscode/pull/56) 104 | 105 | ### 0.5.0 - 2022-08-29 106 | 107 | - Updated to use [Smithy Language Server 0.2.0](https://github.com/awslabs/smithy-language-server/) which adds support for 108 | hover action and Smithy IDL 2 syntax. [#52](https://github.com/awslabs/smithy-vscode/pull/52) 109 | - Added a new file icon for `*.smithy` files. [#51](https://github.com/awslabs/smithy-vscode/pull/51) 110 | 111 | ### 0.4.0 - 2022-06-13 112 | 113 | - Updated to work with Smithy 2.0 syntax. 114 | - Used [Smithy Language Server](https://github.com/awslabs/smithy-language-server/) for language features including: 115 | auto-completion, jump to definition, model validations as diagnostics. [#32](https://github.com/awslabs/smithy-vscode/pull/32) 116 | - Added `Smithy:Selector:Run` and `Smithy:Selector:Clear` commands for highlighting the results of running an 117 | expression on the model in a workspace. [#33](https://github.com/awslabs/smithy-vscode/pull/33) 118 | 119 | ### 0.3.0 - 2020-09-19 120 | 121 | - Updated to work with Smithy 1.0 syntax. 122 | 123 | ### 0.2.0 - 2019-06-26 124 | 125 | - Add support for use statements. 126 | - Add support for documentation comments. 127 | 128 | ### 0.1.0 129 | 130 | Initial release for Smithy IDL syntax highlighting. 131 | -------------------------------------------------------------------------------- /images/smithy_anvil_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smithy-lang/smithy-vscode/600cfcf0db65edce85f02e6d50f5fa2b0862bc8d/images/smithy_anvil_red.png -------------------------------------------------------------------------------- /images/smithy_anvil_red_file_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smithy-lang/smithy-vscode/600cfcf0db65edce85f02e6d50f5fa2b0862bc8d/images/smithy_anvil_red_file_icon.png -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | description 6 | Smithy interface definition language 7 | name 8 | Smithy 9 | uuid 10 | 9c3e617f-4d4a-4370-9194-2e82173c1610 11 | 12 | 13 | -------------------------------------------------------------------------------- /language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//" 4 | }, 5 | // symbols used as brackets 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | // symbols that are auto closed when typing 12 | "autoClosingPairs": [ 13 | ["{", "}"], 14 | ["[", "]"], 15 | ["(", ")"], 16 | ["\"\"\"", "\"\"\""], 17 | ["\"", "\""] 18 | ], 19 | // symbols that that can be used to surround a selection 20 | "surroundingPairs": [ 21 | ["{", "}"], 22 | ["[", "]"], 23 | ["(", ")"], 24 | ["\"\"\"", "\"\"\""], 25 | ["\"", "\""] 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smithy-vscode-extension", 3 | "displayName": "Smithy", 4 | "description": "Smithy IDL Language Extension", 5 | "version": "0.9.0", 6 | "icon": "images/smithy_anvil_red.png", 7 | "publisher": "smithy", 8 | "engines": { 9 | "vscode": "^1.84.1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/smithy-lang/smithy-vscode.git" 14 | }, 15 | "license": "Apache-2.0", 16 | "prettier": { 17 | "tabWidth": 4, 18 | "singleQuote": true, 19 | "printWidth": 120 20 | }, 21 | "categories": [ 22 | "Programming Languages", 23 | "Snippets" 24 | ], 25 | "main": "./out/src/extension", 26 | "preview": true, 27 | "activationEvents": [ 28 | "workspaceContains:**/smithy-build.json", 29 | "workspaceContains:**/*.smithy", 30 | "workspaceContains:**/.smithy-project.json" 31 | ], 32 | "contributes": { 33 | "languages": [ 34 | { 35 | "id": "smithy", 36 | "aliases": [ 37 | "Smithy", 38 | "smithy" 39 | ], 40 | "extensions": [ 41 | ".smithy" 42 | ], 43 | "icon": { 44 | "dark": "./images/smithy_anvil_red_file_icon.png", 45 | "light": "./images/smithy_anvil_red_file_icon.png" 46 | }, 47 | "configuration": "./language-configuration.json" 48 | } 49 | ], 50 | "grammars": [ 51 | { 52 | "language": "smithy", 53 | "scopeName": "source.smithy", 54 | "path": "./syntaxes/smithy.tmLanguage.json" 55 | } 56 | ], 57 | "snippets": [ 58 | { 59 | "language": "smithy", 60 | "path": "./snippets.json" 61 | } 62 | ], 63 | "commands": [ 64 | { 65 | "command": "smithy.runSelector", 66 | "title": "Smithy:Selector:Run" 67 | }, 68 | { 69 | "command": "smithy.clearSelector", 70 | "title": "Smithy:Selector:Clear" 71 | } 72 | ], 73 | "menus": { 74 | "commandPalette": [ 75 | { 76 | "command": "smithy.runSelector", 77 | "when": "editorLangId == smithy" 78 | }, 79 | { 80 | "command": "smithy.clearSelector", 81 | "when": "editorLangId == smithy" 82 | } 83 | ] 84 | }, 85 | "configuration": { 86 | "type": "object", 87 | "title": "Smithy", 88 | "properties": { 89 | "smithyLsp.maxNumberOfProblems": { 90 | "scope": "resource", 91 | "type": "number", 92 | "default": 100, 93 | "description": "Controls the maximum number of problems produced by the server.", 94 | "deprecationMessage": "Use smithy.maxNumberOfProblems instead." 95 | }, 96 | "smithyLsp.trace.server": { 97 | "scope": "window", 98 | "type": "string", 99 | "enum": [ 100 | "off", 101 | "messages", 102 | "verbose" 103 | ], 104 | "default": "verbose", 105 | "description": "Traces the communication between VS Code and the language server.", 106 | "deprecationMessage": "Use smithy.trace.server instead." 107 | }, 108 | "smithyLsp.version": { 109 | "scope": "window", 110 | "type": "string", 111 | "default": null, 112 | "description": "Version of the Smithy Language Server (see https://github.com/smithy-lang/smithy-language-server).", 113 | "deprecationMessage": "Use smithy.server.version instead." 114 | }, 115 | "smithyLsp.diagnostics.minimumSeverity": { 116 | "scope": "window", 117 | "type": "string", 118 | "enum": [ 119 | "NOTE", 120 | "WARNING", 121 | "DANGER", 122 | "ERROR" 123 | ], 124 | "default": null, 125 | "description": "Minimum severity of Smithy validation events to display in the editor.", 126 | "deprecationMessage": "Use smithy.server.diagnostics.minimumSeverity instead." 127 | }, 128 | "smithyLsp.onlyReloadOnSave": { 129 | "scope": "window", 130 | "type": "boolean", 131 | "default": false, 132 | "description": "Whether to only re-load the Smithy model on save. Use this if the server feels slow as you type.", 133 | "deprecationMessage": "May cause features like definition, hover, and completions to behave incorrectly when you have unsaved changes." 134 | }, 135 | "smithy.maxNumberOfProblems": { 136 | "scope": "resource", 137 | "type": "number", 138 | "default": 100, 139 | "description": "Controls the maximum number of problems produced by the server." 140 | }, 141 | "smithy.trace.server": { 142 | "type": "string", 143 | "enum": [ 144 | "off", 145 | "messages", 146 | "verbose" 147 | ], 148 | "default": "verbose", 149 | "description": "Traces the communication between VS Code and the language server." 150 | }, 151 | "smithy.server.executable": { 152 | "type": "string", 153 | "default": null, 154 | "description": "Executable to run the Smithy Language Server. Can be the executable name if it is on your PATH, or an absolute path to the executable." 155 | }, 156 | "smithy.server.version": { 157 | "type": "string", 158 | "default": "0.7.0", 159 | "description": "Version of the Smithy Language Server to use. Ignored if smithy.server.executable is provided." 160 | }, 161 | "smithy.server.diagnostics.minimumSeverity": { 162 | "type": "string", 163 | "enum": [ 164 | "NOTE", 165 | "WARNING", 166 | "DANGER", 167 | "ERROR" 168 | ], 169 | "default": "WARNING", 170 | "description": "Minimum severity of Smithy validation events to display in the editor." 171 | } 172 | } 173 | } 174 | }, 175 | "scripts": { 176 | "vscode:prepublish": "npm run webpack-package", 177 | "webpack-package": "webpack --mode production --devtool hidden-source-map", 178 | "compile": "tsc -p ./", 179 | "install-plugin": "npm run package && code --install-extension smithy-vscode.vsix", 180 | "uninstall-plugin": "code --uninstall-extension smithy.smithy-vscode-extension", 181 | "package": "vsce package -o smithy-vscode.vsix", 182 | "format": "prettier --write '**/*.{ts,js,json}'", 183 | "format-check": "prettier --check '**/*.{ts,js,json}'", 184 | "test-grammar": "npx vscode-tmgrammar-test -g syntaxes/smithy.tmLanguage.json 'tests/grammar/*'", 185 | "test-extension": "npm run compile && npm run package && node ./out/tests/runTest.js", 186 | "test": "npm run format-check && npm run test-grammar && npm run test-extension" 187 | }, 188 | "devDependencies": { 189 | "@types/follow-redirects": "^1.14.4", 190 | "@types/glob": "^8.1.0", 191 | "@types/mocha": "^10.0.4", 192 | "@types/node": "^18.18.9", 193 | "@types/sinon": "^10.0.20", 194 | "@types/vscode": "^1.84.1", 195 | "@vscode/test-electron": "^2.4.0", 196 | "@vscode/vsce": "^2.22.0", 197 | "glob": "^9.3.5", 198 | "mocha": "^10.8.2", 199 | "prettier": "^2.8.8", 200 | "sinon": "^15.2.0", 201 | "ts-loader": "^9.5.0", 202 | "typescript": "^5.2.2", 203 | "vscode-nls-dev": "^4.0.4", 204 | "vscode-tmgrammar-test": "^0.1.2", 205 | "webpack": "^5.94.0", 206 | "webpack-cli": "^5.1.4" 207 | }, 208 | "dependencies": { 209 | "follow-redirects": "^1.15.6", 210 | "vscode-languageclient": "^8.1.0", 211 | "vscode-nls": "^5.2.0" 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "Add Service": { 3 | "prefix": "service", 4 | "body": "service ${1:MyService} {\n version: \"${2:MyVersion}\"\n operations: [${3:MyOperation}]\n resources: [${4:MyResource}]\n errors: [${0:MyError}]\n}", 5 | "description": "Adds a service with version, operations, resources and errors properties" 6 | }, 7 | "Add Resource based Service": { 8 | "prefix": "service", 9 | "body": "service ${1:MyService} {\n version: \"${2:version}\"\n resources: [${3:MyResource}]\n errors: [${0:MyError}]\n}", 10 | "description": "Adds a service with version, resources and errors properties" 11 | }, 12 | "Add Operation based Service": { 13 | "prefix": "service", 14 | "body": "service ${1:MyService} {\n version: \"${2:MyVersion}\"\n operations: [${3:MyOperation}]\n errors: [${0:MyError}]\n}", 15 | "description": "Adds a service with version, operations and errors properties" 16 | }, 17 | "Add Operation": { 18 | "prefix": "operation", 19 | "body": "operation ${1:MyOperation} {\n input: ${2:MyInput}\n output: ${3:MyOutput}\n errors: [${0:MyError}]\n}", 20 | "description": "Adds an operation with input, output and errors properties" 21 | }, 22 | "Add lifecycle Resource": { 23 | "prefix": "resource", 24 | "body": "resource ${1:MyResource} {\n identifiers: { ${2:myIdentifierKey1}: ${3:MyIdentifierString} }\n create: ${4:MyCreateOperation}\n put: ${5:MyPutOperation}\n read: ${6:MyReadOperation}\n update: ${7:MyUpdateOperation}\n delete: ${8:MyDeleteOperation}\n list: ${0:MyListOperation}\n}", 25 | "description": "Adds a resource with identifiers and lifecycle operations" 26 | }, 27 | "Add identifier only Resource": { 28 | "prefix": "resource", 29 | "body": "resource ${1:MyResource} {\n identifiers: { ${2:myIdentifierKey1}: ${0:MyIdentifierString} }\n}", 30 | "description": "Adds a resource with identifiers only" 31 | }, 32 | "Add List shape": { 33 | "prefix": "list", 34 | "body": "list ${1:MyList} {\n member: ${0:MyListMember}\n}", 35 | "description": "Adds a list shape" 36 | }, 37 | "Add Set shape": { 38 | "prefix": "set", 39 | "body": "set ${1:MySet} {\n member: ${0:MySetMember}\n}", 40 | "description": "Adds a set shape" 41 | }, 42 | "Add Map shape": { 43 | "prefix": "map", 44 | "body": "map ${1:MyMap} {\n key: ${2:MyStringKey}\n value: ${0:MyValue}\n}", 45 | "description": "Adds a map shape" 46 | }, 47 | "Add Structure shape": { 48 | "prefix": "structure", 49 | "body": "structure ${0:MyStructure} {\n}", 50 | "description": "Adds a structure shape" 51 | }, 52 | "Add @input Structure shape": { 53 | "prefix": "@input", 54 | "body": "@input\nstructure ${1:MyStructure} {$0}", 55 | "description": "Adds a structure shape with the @input trait" 56 | }, 57 | "Add @output Structure shape": { 58 | "prefix": "@output", 59 | "body": "@output\nstructure ${1:MyStructure} {$0}", 60 | "description": "Adds a structure shape with the @output trait" 61 | }, 62 | "Add Union shape": { 63 | "prefix": "union", 64 | "body": "union ${1:myUnion} {\n ${2:myVariantA}: ${3:MyVariantTargetA}\n ${4:myVariantB}: ${0:MyVariantTargetB}\n}", 65 | "description": "Adds a union shape" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export function getServerDiagnosticsMinimumSeverity(): string | undefined { 4 | return getOldOrNewConfig('diagnostics.minimumSeverity', 'server.diagnostics.minimumSeverity'); 5 | } 6 | 7 | export function getServerOnlyReloadOnSave(): boolean | undefined { 8 | return getOldConfig('onlyReloadOnSave'); 9 | } 10 | 11 | export function getServerExecutable(): string | undefined { 12 | return getConfig('server.executable'); 13 | } 14 | 15 | export function getServerVersion(): string { 16 | return getOldOrNewConfig('version', 'server.version'); 17 | } 18 | 19 | function getOldOrNewConfig(oldKey: string, newKey: string): T | undefined { 20 | return getOldConfig(oldKey) || getConfig(newKey); 21 | } 22 | 23 | function getConfig(key: string): T | undefined { 24 | return vscode.workspace.getConfiguration('smithy').get(key); 25 | } 26 | 27 | function getOldConfig(key: string): T | undefined { 28 | return vscode.workspace.getConfiguration('smithyLsp').get(key); 29 | } 30 | -------------------------------------------------------------------------------- /src/coursier/coursier.ts: -------------------------------------------------------------------------------- 1 | import * as child_process from 'child_process'; 2 | import * as vscode from 'vscode'; 3 | import downloadCoursierIfRequired from './download-coursier'; 4 | 5 | export default async function getCoursierExecutable(context: vscode.ExtensionContext): Promise { 6 | for (const command of ['cs', 'coursier']) { 7 | if (await availableOnPath(command, ['--help'])) { 8 | return command; 9 | } 10 | } 11 | 12 | console.log('Coursier not found on path, downloading it instead.'); 13 | return await downloadCoursierIfRequired(context.globalStoragePath, 'v2.0.6'); 14 | } 15 | 16 | function availableOnPath(command: string, args: string[]): Promise { 17 | return new Promise((resolve, reject) => { 18 | child_process.execFile(command, args, (e, _, __) => { 19 | resolve(e == null); 20 | }); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /src/coursier/download-coursier.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { https } from 'follow-redirects'; 3 | import { IncomingMessage } from 'http'; 4 | import * as fs from 'fs'; 5 | import { access, mkdir } from 'fs/promises'; 6 | 7 | export default function downloadCoursierIfRequired(extensionPath: string, versionPath: string): Promise { 8 | function binPath(filename: string) { 9 | return path.join(extensionPath, filename); 10 | } 11 | 12 | function createDir() { 13 | return mkdir(extensionPath).catch((err: { code?: string }) => { 14 | return err && err.code === 'EEXIST' ? Promise.resolve() : Promise.reject(err); 15 | }); 16 | } 17 | 18 | const urls = { 19 | darwin: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-apple-darwin`, 20 | linux: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-pc-linux`, 21 | win32: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-pc-win32.exe`, 22 | }; 23 | const targets = { 24 | darwin: binPath('coursier'), 25 | linux: binPath('coursier'), 26 | win32: binPath('coursier.exe'), 27 | }; 28 | 29 | const targetFile = targets[process.platform]; 30 | return validBinFileExists(targetFile).then((valid) => { 31 | return valid ? targetFile : createDir().then(() => downloadFile(urls[process.platform], targetFile)); 32 | }); 33 | } 34 | 35 | function validBinFileExists(file: string): Promise { 36 | return access(file, fs.constants.X_OK) 37 | .then(() => true) 38 | .catch(() => false); 39 | } 40 | 41 | function downloadFile(url: string, targetFile: string): Promise { 42 | function promiseGet(url: string): Promise { 43 | return new Promise((resolve, reject) => { 44 | https.get(url, (response) => { 45 | if (response.statusCode === 200) { 46 | resolve(response); 47 | } else { 48 | reject(new Error(`Server responded with ${response.statusCode}: ${response.statusMessage}`)); 49 | } 50 | }); 51 | }); 52 | } 53 | 54 | function writeToDisk(response: IncomingMessage): Promise { 55 | return new Promise((resolve, reject) => { 56 | const file = fs.createWriteStream(targetFile, { 57 | flags: 'wx', 58 | mode: 0o755, 59 | }); 60 | response.pipe(file); 61 | 62 | file.on('finish', () => { 63 | console.log(`Finished downloaded file at ${targetFile}`); 64 | resolve(targetFile); 65 | }); 66 | 67 | file.on('error', (err: { code: string | undefined }) => { 68 | if (file) { 69 | file.close(); 70 | fs.unlink(targetFile, () => {}); // Delete temp file 71 | } 72 | 73 | if (err.code === 'EEXIST') { 74 | console.log(`File already exists at ${targetFile}`); 75 | resolve(targetFile); 76 | } else { 77 | console.error(`File error while downloading file at ${targetFile}`); 78 | console.error(err); 79 | reject(err); 80 | } 81 | }); 82 | }); 83 | } 84 | // adapted from https://stackoverflow.com/a/45007624 85 | return promiseGet(url).then((resp) => writeToDisk(resp)); 86 | } 87 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as lsp from 'vscode-languageclient/node'; 3 | 4 | import * as config from './config'; 5 | import JarFileContentsProvider from './jar-file-contents'; 6 | import SelectorHandler from './selector'; 7 | import getCoursierExecutable from './coursier/coursier'; 8 | 9 | let client: lsp.LanguageClient; 10 | 11 | export async function activate(context: vscode.ExtensionContext) { 12 | const server = await getServer(context); 13 | const clientOptions = getClientOptions(); 14 | 15 | // Create the language client and start the client. 16 | client = new lsp.LanguageClient('smithy', 'Smithy', server, clientOptions); 17 | 18 | const jarFileContentsProvider = new JarFileContentsProvider(client); 19 | const selectorHandler = new SelectorHandler(client); 20 | 21 | context.subscriptions.push( 22 | vscode.workspace.registerTextDocumentContentProvider('smithyjar', jarFileContentsProvider), 23 | vscode.commands.registerCommand('smithy.runSelector', selectorHandler.run, selectorHandler), 24 | vscode.commands.registerCommand('smithy.clearSelector', selectorHandler.clear, selectorHandler) 25 | ); 26 | 27 | // Start the client. This will also launch the server 28 | client.start(); 29 | } 30 | 31 | export function deactivate(): Thenable | undefined { 32 | if (!client) { 33 | return undefined; 34 | } 35 | return client.stop(); 36 | } 37 | 38 | function getClientOptions(): lsp.LanguageClientOptions { 39 | const initializationOptions = { 40 | 'diagnostics.minimumSeverity': config.getServerDiagnosticsMinimumSeverity(), 41 | onlyReloadOnSave: config.getServerOnlyReloadOnSave(), 42 | }; 43 | 44 | return { 45 | outputChannelName: 'Smithy Language Server', 46 | // Don't switch to output window when the server returns output. 47 | revealOutputChannelOn: lsp.RevealOutputChannelOn.Never, 48 | progressOnInitialization: true, 49 | 50 | documentSelector: [ 51 | { language: 'smithy' }, 52 | { scheme: 'smithyjar' }, 53 | { pattern: '**/{smithy-build,.smithy-project}.json' }, 54 | ], 55 | 56 | initializationOptions, 57 | }; 58 | } 59 | 60 | // Couriser uses an index to determine where to download jvms from: https://get-coursier.io/docs/2.0.6/cli-java#jvm-index 61 | // Newer versions of coursier use this index, which is more up to date than the one 62 | // used by the coursier version used by the extension. 63 | // This is a temporary solution to avoid adding logic that determines the version of 64 | // coursier on the local machine. In the near future, we will vend the language server 65 | // as a standalone executable, and will no longer need couriser to manage the jvm version. 66 | const COURSIER_JVM_INDEX = 'https://raw.githubusercontent.com/coursier/jvm-index/master/index.json'; 67 | 68 | async function getServer(context: vscode.ExtensionContext): Promise { 69 | const serverExecutable = config.getServerExecutable(); 70 | if (serverExecutable) { 71 | return { 72 | command: serverExecutable, 73 | args: ['0'], 74 | }; 75 | } else { 76 | const coursierExecutable = await getCoursierExecutable(context); 77 | const languageServerVersion = config.getServerVersion(); 78 | return { 79 | command: coursierExecutable, 80 | args: [ 81 | 'launch', 82 | 'software.amazon.smithy:smithy-language-server:' + languageServerVersion, 83 | // Configure couriser to use java 21 84 | '--jvm', 85 | // By default, coursier uses AdoptOpenJDK: https://get-coursier.io/docs/2.0.6/cli-java 86 | // We could just say '21' here, and let coursier default to adopt jdk 87 | // 21, but later versions of the jdk are released under the name adoptium. 88 | 'corretto:21', 89 | // The location to download the jvm from is provided by the jvm index. 90 | '--jvm-index', 91 | COURSIER_JVM_INDEX, 92 | '-r', 93 | 'm2local', 94 | '-M', 95 | 'software.amazon.smithy.lsp.Main', 96 | '--', 97 | '0', 98 | ], 99 | }; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/jar-file-contents.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as lsp from 'vscode-languageclient/node'; 3 | 4 | namespace JarFileContentsRequest { 5 | type Params = lsp.TextDocumentIdentifier; 6 | 7 | type Result = string; 8 | 9 | const method = 'smithy/jarFileContents'; 10 | 11 | export const type = new lsp.RequestType(method); 12 | } 13 | 14 | export default class JarFileContentsProvider implements vscode.TextDocumentContentProvider { 15 | private client: lsp.LanguageClient; 16 | 17 | constructor(client: lsp.LanguageClient) { 18 | this.client = client; 19 | } 20 | 21 | provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): vscode.ProviderResult { 22 | return this.client.sendRequest(JarFileContentsRequest.type, { uri: uri.toString() }, token); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/selector.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as lsp from 'vscode-languageclient/node'; 3 | 4 | namespace SelectorCommandRequest { 5 | type Params = { 6 | expression: string; 7 | }; 8 | 9 | type Result = lsp.Location[]; 10 | 11 | const method = 'smithy/selectorCommand'; 12 | 13 | export const type = new lsp.RequestType(method); 14 | } 15 | 16 | export default class SelectorHandler { 17 | private client: lsp.LanguageClient; 18 | private expression: string = 'Enter selector expression'; 19 | private decorationType: vscode.TextEditorDecorationType; 20 | 21 | constructor(client: lsp.LanguageClient) { 22 | this.client = client; 23 | this.decorationType = createDecorationType(); 24 | } 25 | 26 | async run() { 27 | const expression = await vscode.window.showInputBox({ 28 | title: 'Run a selector', 29 | value: this.expression, 30 | }); 31 | 32 | // Don't do anything if expression was not populated. 33 | if (!expression) { 34 | return; 35 | } 36 | 37 | // Don't do anything if there's no active editor. 38 | const activeEditor = vscode.window.activeTextEditor; 39 | if (!activeEditor) { 40 | return; 41 | } 42 | 43 | await this.clear(); 44 | this.expression = expression; 45 | 46 | const response = await this.client.sendRequest(SelectorCommandRequest.type, { expression }); 47 | 48 | const ranges: vscode.Range[] = []; 49 | for (const location of response) { 50 | if (location.uri.endsWith(activeEditor.document.fileName)) { 51 | const range = new vscode.Range( 52 | location.range.start.line, 53 | location.range.start.character, 54 | location.range.end.line, 55 | location.range.end.character 56 | ); 57 | ranges.push(range); 58 | } 59 | } 60 | 61 | activeEditor.setDecorations(this.decorationType, ranges); 62 | } 63 | 64 | async clear() { 65 | this.decorationType.dispose(); 66 | this.decorationType = createDecorationType(); 67 | } 68 | } 69 | 70 | function createDecorationType(): vscode.TextEditorDecorationType { 71 | return vscode.window.createTextEditorDecorationType({ 72 | border: 'dotted', 73 | borderColor: '#C44536', 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /syntaxes/smithy.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Smithy", 3 | "fileTypes": ["smithy"], 4 | "scopeName": "source.smithy", 5 | "uuid": "9c3e617f-4d4a-4370-9194-2e82173c1610", 6 | "foldingStartMarker": "(\\{|\\[)\\s*", 7 | "foldingStopMarker": "\\s*(\\}|\\])", 8 | "patterns": [ 9 | { 10 | "include": "#comment" 11 | }, 12 | { 13 | "name": "meta.keyword.statement.control.smithy", 14 | "begin": "^(\\$)([A-Z-a-z_][A-Z-a-z0-9_]*)(:)\\s*", 15 | "end": "\\n", 16 | "beginCaptures": { 17 | "1": { 18 | "name": "keyword.statement.control.smithy" 19 | }, 20 | "2": { 21 | "name": "support.type.property-name.smithy" 22 | }, 23 | "3": { 24 | "name": "punctuation.separator.dictionary.pair.smithy" 25 | } 26 | }, 27 | "patterns": [ 28 | { 29 | "include": "#value" 30 | }, 31 | { 32 | "match": "[^\\n]", 33 | "name": "invalid.illegal.control.smithy" 34 | } 35 | ] 36 | }, 37 | { 38 | "name": "meta.keyword.statement.metadata.smithy", 39 | "begin": "^(metadata)\\s+(.+)\\s*(=)\\s*", 40 | "beginCaptures": { 41 | "1": { 42 | "name": "keyword.statement.smithy" 43 | }, 44 | "2": { 45 | "name": "variable.other.smithy" 46 | }, 47 | "3": { 48 | "name": "keyword.operator.smithy" 49 | } 50 | }, 51 | "end": "\\n", 52 | "patterns": [ 53 | { 54 | "include": "#value" 55 | } 56 | ] 57 | }, 58 | { 59 | "name": "meta.keyword.statement.namespace.smithy", 60 | "begin": "^(namespace)\\s+", 61 | "beginCaptures": { 62 | "1": { 63 | "name": "keyword.statement.smithy" 64 | } 65 | }, 66 | "end": "\\n", 67 | "patterns": [ 68 | { 69 | "match": "[A-Z-a-z_][A-Z-a-z0-9_]*(\\.[A-Z-a-z_][A-Z-a-z0-9_]*)*", 70 | "name": "entity.name.type.smithy" 71 | }, 72 | { 73 | "match": "[^\\n]", 74 | "name": "invalid.illegal.namespace.smithy" 75 | } 76 | ] 77 | }, 78 | { 79 | "name": "meta.keyword.statement.use.smithy", 80 | "begin": "^(use)\\s+", 81 | "beginCaptures": { 82 | "1": { 83 | "name": "keyword.statement.smithy" 84 | } 85 | }, 86 | "end": "\\n", 87 | "patterns": [ 88 | { 89 | "match": "[A-Z-a-z_][A-Z-a-z0-9_]*(\\.[A-Z-a-z_][A-Z-a-z0-9_]*)*#[A-Z-a-z_][A-Z-a-z0-9_]*(\\.[A-Z-a-z_][A-Z-a-z0-9_]*)*", 90 | "name": "entity.name.type.smithy" 91 | }, 92 | { 93 | "match": "[^\\n]", 94 | "name": "invalid.illegal.use.smithy" 95 | } 96 | ] 97 | }, 98 | { 99 | "include": "#trait" 100 | }, 101 | { 102 | "name": "meta.keyword.statement.shape.smithy", 103 | "begin": "^(byte|short|integer|long|float|double|bigInteger|bigDecimal|boolean|blob|string|timestamp|document|list|set|map|union|service|operation|resource|enum|intEnum)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)\\s+(with)\\s+(\\[)", 104 | "beginCaptures": { 105 | "1": { 106 | "name": "keyword.statement.smithy" 107 | }, 108 | "2": { 109 | "name": "entity.name.type.smithy" 110 | }, 111 | "3": { 112 | "name": "keyword.statement.with.smithy" 113 | }, 114 | "4": { 115 | "name": "punctuation.definition.array.begin.smithy" 116 | } 117 | }, 118 | "end": "\\]", 119 | "endCaptures": { 120 | "0": { 121 | "name": "punctuation.definition.array.end.smithy" 122 | } 123 | }, 124 | "patterns": [ 125 | { 126 | "include": "#identifier", 127 | "name": "entity.name.type.smithy" 128 | }, 129 | { 130 | "include": "#comment" 131 | }, 132 | { 133 | "match": ",", 134 | "name": "punctuation.separator.array.smithy" 135 | } 136 | ] 137 | }, 138 | { 139 | "name": "meta.keyword.statement.shape.smithy", 140 | "match": "^(byte|short|integer|long|float|double|bigInteger|bigDecimal|boolean|blob|string|timestamp|document|list|set|map|union|service|operation|resource|enum|intEnum)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)", 141 | "captures": { 142 | "1": { 143 | "name": "keyword.statement.smithy" 144 | }, 145 | "2": { 146 | "name": "entity.name.type.smithy" 147 | } 148 | } 149 | }, 150 | { 151 | "name": "meta.keyword.statement.shape.smithy", 152 | "begin": "^(structure)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)(?:\\s+(for)\\s+([0-9a-zA-Z\\.#-]+))?\\s+(with)\\s+(\\[)", 153 | "beginCaptures": { 154 | "1": { 155 | "name": "keyword.statement.smithy" 156 | }, 157 | "2": { 158 | "name": "entity.name.type.smithy" 159 | }, 160 | "3": { 161 | "name": "keyword.statement.for-resource.smithy" 162 | }, 163 | "4": { 164 | "name": "entity.name.type.smithy" 165 | }, 166 | "5": { 167 | "name": "keyword.statement.with.smithy" 168 | }, 169 | "6": { 170 | "name": "punctuation.definition.array.begin.smithy" 171 | } 172 | }, 173 | "end": "\\]", 174 | "endCaptures": { 175 | "0": { 176 | "name": "punctuation.definition.array.end.smithy" 177 | } 178 | }, 179 | "patterns": [ 180 | { 181 | "include": "#identifier", 182 | "name": "entity.name.type.smithy" 183 | }, 184 | { 185 | "include": "#comment" 186 | }, 187 | { 188 | "match": ",", 189 | "name": "punctuation.separator.array.smithy" 190 | } 191 | ] 192 | }, 193 | { 194 | "name": "meta.keyword.statement.shape.smithy", 195 | "match": "^(structure)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)(?:\\s+(for)\\s+([0-9a-zA-Z\\.#-]+))?", 196 | "captures": { 197 | "1": { 198 | "name": "keyword.statement.smithy" 199 | }, 200 | "2": { 201 | "name": "entity.name.type.smithy" 202 | }, 203 | "3": { 204 | "name": "keyword.statement.for-resource.smithy" 205 | }, 206 | "4": { 207 | "name": "entity.name.type.smithy" 208 | } 209 | } 210 | }, 211 | { 212 | "begin": "\\{", 213 | "beginCaptures": { 214 | "0": { 215 | "name": "punctuation.definition.dictionary.begin.smithy" 216 | } 217 | }, 218 | "end": "\\}", 219 | "endCaptures": { 220 | "0": { 221 | "name": "punctuation.definition.dictionary.end.smithy" 222 | } 223 | }, 224 | "patterns": [ 225 | { 226 | "include": "#shape_inner" 227 | } 228 | ] 229 | }, 230 | { 231 | "name": "meta.keyword.statement.apply.smithy", 232 | "begin": "^(apply)\\s+", 233 | "end": "\\n", 234 | "beginCaptures": { 235 | "1": { 236 | "name": "keyword.statement.smithy" 237 | } 238 | }, 239 | "patterns": [ 240 | { 241 | "include": "#trait" 242 | }, 243 | { 244 | "include": "#shapeid" 245 | }, 246 | { 247 | "match": "[^\\n]", 248 | "name": "invalid.illegal.apply.smithy" 249 | } 250 | ] 251 | }, 252 | { 253 | "name": "meta.keyword.statement.member.smithy", 254 | "begin": "^([A-Z-a-z_][A-Z-a-z0-9_]*)(:)\\s*", 255 | "end": "\\n", 256 | "beginCaptures": { 257 | "1": { 258 | "name": "support.type.property-name.smithy" 259 | }, 260 | "2": { 261 | "name": "punctuation.separator.dictionary.pair.smithy" 262 | } 263 | }, 264 | "patterns": [ 265 | { 266 | "include": "#shapeid" 267 | } 268 | ] 269 | } 270 | ], 271 | "repository": { 272 | "with_statement": { 273 | "begin": "(with)\\s+(\\[)", 274 | "beginCaptures": { 275 | "1": { 276 | "name": "keyword.statement.with.smithy" 277 | }, 278 | "2": { 279 | "name": "punctuation.definition.array.begin.smithy" 280 | } 281 | }, 282 | "end": "\\]", 283 | "endCaptures": { 284 | "0": { 285 | "name": "punctuation.definition.array.end.smithy" 286 | } 287 | }, 288 | "patterns": [ 289 | { 290 | "match": ",", 291 | "name": "punctuation.separator.array.smithy" 292 | }, 293 | { 294 | "include": "#identifier" 295 | }, 296 | { 297 | "include": "#comment" 298 | } 299 | ] 300 | }, 301 | "comment": { 302 | "patterns": [ 303 | { 304 | "include": "#doc_comment" 305 | }, 306 | { 307 | "include": "#line_comment" 308 | } 309 | ] 310 | }, 311 | "doc_comment": { 312 | "match": "(///.*)", 313 | "name": "comment.block.documentation.smithy" 314 | }, 315 | "line_comment": { 316 | "match": "(//.*)", 317 | "name": "comment.line.double-slash.smithy" 318 | }, 319 | "trait": { 320 | "patterns": [ 321 | { 322 | "name": "meta.keyword.statement.trait.smithy", 323 | "begin": "(@)([0-9a-zA-Z\\.#-]+)(\\()", 324 | "beginCaptures": { 325 | "1": { 326 | "name": "punctuation.definition.annotation.smithy" 327 | }, 328 | "2": { 329 | "name": "storage.type.annotation.smithy" 330 | }, 331 | "3": { 332 | "name": "punctuation.definition.dictionary.begin.smithy" 333 | } 334 | }, 335 | "end": "\\)", 336 | "endCaptures": { 337 | "0": { 338 | "name": "punctuation.definition.dictionary.end.smithy" 339 | } 340 | }, 341 | "patterns": [ 342 | { 343 | "include": "#object_inner" 344 | }, 345 | { 346 | "include": "#value" 347 | } 348 | ] 349 | }, 350 | { 351 | "name": "meta.keyword.statement.trait.smithy", 352 | "match": "(@)([0-9a-zA-Z\\.#-]+)", 353 | "captures": { 354 | "1": { 355 | "name": "punctuation.definition.annotation.smithy" 356 | }, 357 | "2": { 358 | "name": "storage.type.annotation.smithy" 359 | } 360 | } 361 | } 362 | ] 363 | }, 364 | "value": { 365 | "patterns": [ 366 | { 367 | "include": "#comment" 368 | }, 369 | { 370 | "include": "#keywords" 371 | }, 372 | { 373 | "include": "#number" 374 | }, 375 | { 376 | "include": "#string" 377 | }, 378 | { 379 | "include": "#array" 380 | }, 381 | { 382 | "include": "#object" 383 | } 384 | ] 385 | }, 386 | "array": { 387 | "begin": "\\[", 388 | "beginCaptures": { 389 | "0": { 390 | "name": "punctuation.definition.array.begin.smithy" 391 | } 392 | }, 393 | "end": "\\]", 394 | "endCaptures": { 395 | "0": { 396 | "name": "punctuation.definition.array.end.smithy" 397 | } 398 | }, 399 | "name": "meta.structure.array.smithy", 400 | "patterns": [ 401 | { 402 | "include": "#value" 403 | }, 404 | { 405 | "match": ",", 406 | "name": "punctuation.separator.array.smithy" 407 | }, 408 | { 409 | "match": "[^\\s\\]]", 410 | "name": "invalid.illegal.array.smithy" 411 | } 412 | ] 413 | }, 414 | "keywords": { 415 | "match": "\\b(?:true|false|null)\\b", 416 | "name": "constant.language.smithy" 417 | }, 418 | "number": { 419 | "match": "(?x: # turn on extended mode\n -? # an optional minus\n (?:\n 0 # a zero\n | # ...or...\n [1-9] # a 1-9 character\n \\d* # followed by zero or more digits\n )\n (?:\n (?:\n \\. # a period\n \\d+ # followed by one or more digits\n )?\n (?:\n [eE] # an e character\n [+-]? # followed by an option +/-\n \\d+ # followed by one or more digits\n )? # make exponent optional\n )? # make decimal portion optional\n )", 420 | "name": "constant.numeric.smithy" 421 | }, 422 | "object": { 423 | "begin": "\\{", 424 | "beginCaptures": { 425 | "0": { 426 | "name": "punctuation.definition.dictionary.begin.smithy" 427 | } 428 | }, 429 | "end": "\\}", 430 | "endCaptures": { 431 | "0": { 432 | "name": "punctuation.definition.dictionary.end.smithy" 433 | } 434 | }, 435 | "name": "meta.structure.dictionary.smithy", 436 | "patterns": [ 437 | { 438 | "include": "#object_inner" 439 | } 440 | ] 441 | }, 442 | "object_inner": { 443 | "patterns": [ 444 | { 445 | "include": "#comment" 446 | }, 447 | { 448 | "include": "#string_key" 449 | }, 450 | { 451 | "match": ":", 452 | "name": "punctuation.separator.dictionary.key-value.smithy" 453 | }, 454 | { 455 | "match": "=", 456 | "name": "keyword.operator.smithy" 457 | }, 458 | { 459 | "name": "meta.structure.dictionary.value.smithy", 460 | "include": "#value" 461 | }, 462 | { 463 | "match": ",", 464 | "name": "punctuation.separator.dictionary.pair.smithy" 465 | } 466 | ] 467 | }, 468 | "shape_inner": { 469 | "patterns": [ 470 | { 471 | "include": "#trait" 472 | }, 473 | { 474 | "match": ":=", 475 | "name": "punctuation.separator.dictionary.inline-struct.smithy" 476 | }, 477 | { 478 | "include": "#with_statement" 479 | }, 480 | { 481 | "include": "#elided_target" 482 | }, 483 | { 484 | "include": "#object_inner" 485 | } 486 | ] 487 | }, 488 | "string_key": { 489 | "patterns": [ 490 | { 491 | "include": "#identifier_key" 492 | }, 493 | { 494 | "include": "#dquote_key" 495 | } 496 | ] 497 | }, 498 | "identifier_key": { 499 | "name": "support.type.property-name.smithy", 500 | "match": "[A-Z-a-z0-9_\\.#$]+(?=\\s*:)" 501 | }, 502 | "dquote_key": { 503 | "name": "support.type.property-name.smithy", 504 | "match": "\".*\"(?=\\s*:)" 505 | }, 506 | "string": { 507 | "patterns": [ 508 | { 509 | "include": "#textblock" 510 | }, 511 | { 512 | "include": "#dquote" 513 | }, 514 | { 515 | "include": "#shapeid" 516 | } 517 | ] 518 | }, 519 | "textblock": { 520 | "name": "string.quoted.double.smithy", 521 | "begin": "\"\"\"", 522 | "beginCaptures": { 523 | "0": { 524 | "name": "punctuation.definition.string.begin.smithy" 525 | } 526 | }, 527 | "end": "\"\"\"", 528 | "endCaptures": { 529 | "0": { 530 | "name": "punctuation.definition.string.end.smithy" 531 | } 532 | }, 533 | "patterns": [ 534 | { 535 | "match": "\\\\.", 536 | "name": "constant.character.escape.smithy" 537 | } 538 | ] 539 | }, 540 | "dquote": { 541 | "name": "string.quoted.double.smithy", 542 | "begin": "\"", 543 | "beginCaptures": { 544 | "0": { 545 | "name": "punctuation.definition.string.begin.smithy" 546 | } 547 | }, 548 | "end": "\"", 549 | "endCaptures": { 550 | "0": { 551 | "name": "punctuation.definition.string.end.smithy" 552 | } 553 | }, 554 | "patterns": [ 555 | { 556 | "match": "\\\\.", 557 | "name": "constant.character.escape.smithy" 558 | } 559 | ] 560 | }, 561 | "identifier": { 562 | "name": "entity.name.type.smithy", 563 | "match": "[A-Z-a-z_][A-Z-a-z0-9_]*" 564 | }, 565 | "shapeid": { 566 | "name": "entity.name.type.smithy", 567 | "match": "[A-Z-a-z_][A-Z-a-z0-9_\\.#$]*" 568 | }, 569 | "elided_target": { 570 | "match": "(\\$)([A-Z-a-z0-9_\\.#$]+)", 571 | "captures": { 572 | "1": { 573 | "name": "keyword.statement.elision.smithy" 574 | }, 575 | "2": { 576 | "name": "support.type.property-name.smithy" 577 | } 578 | } 579 | } 580 | } 581 | } 582 | -------------------------------------------------------------------------------- /test-fixtures/suite1/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "smithyLsp.logToFile": "enabled" 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/suite1/main.smithy: -------------------------------------------------------------------------------- 1 | $version: "2.0" 2 | 3 | namespace example.weather 4 | 5 | use aws.api#dataPlane 6 | use aws.api#service 7 | 8 | /// Provides weather forecasts. 9 | @service( 10 | sdkId: "Weather", 11 | ) 12 | service Weather { 13 | version: "2006-03-01" 14 | operations: [GetCurrentTime] 15 | } 16 | 17 | @readonly 18 | @dataPlane 19 | operation GetCurrentTime { 20 | input := {} 21 | output := { 22 | @required 23 | time: Timestamp 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test-fixtures/suite1/smithy-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "sources": ["./main.smithy"], 4 | "maven": { 5 | "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], 6 | "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test-fixtures/suite2/main.smithy: -------------------------------------------------------------------------------- 1 | $version: "2.0" 2 | 3 | namespace example.weather 4 | 5 | apply smithy.api#String @deprecated -------------------------------------------------------------------------------- /test-fixtures/suite2/smithy-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "sources": ["./main.smithy"], 4 | "maven": { 5 | "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], 6 | "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test-fixtures/suite3/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "smithyLsp.logToFile": "enabled" 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/suite3/main.smithy: -------------------------------------------------------------------------------- 1 | $version: "2.0" 2 | 3 | namespace example.weather 4 | 5 | /// Provides weather forecasts. 6 | @paginated(inputToken: "nextToken", outputToken: "nextToken", 7 | pageSize: "pageSize") 8 | service Weather { 9 | version: "2006-03-01" 10 | resources: [City] 11 | operations: [GetCurrentTime] 12 | } 13 | 14 | resource City { 15 | identifiers: { cityId: CityId } 16 | read: GetCity 17 | list: ListCities 18 | resources: [Forecast] 19 | } 20 | 21 | resource Forecast { 22 | identifiers: { cityId: CityId } 23 | read: GetForecast 24 | } 25 | 26 | // "pattern" is a trait. 27 | @pattern("^[A-Za-z0-9 ]+$") 28 | string CityId 29 | 30 | @readonly 31 | operation GetCity { 32 | input: GetCityInput 33 | output: GetCityOutput 34 | errors: [NoSuchResource] 35 | } 36 | 37 | @input 38 | structure GetCityInput { 39 | // "cityId" provides the identifier for the resource and 40 | // has to be marked as required. 41 | @required 42 | cityId: CityId 43 | } 44 | 45 | @output 46 | structure GetCityOutput { 47 | // "required" is used on output to indicate if the service 48 | // will always provide a value for the member. 49 | @required 50 | name: String 51 | 52 | @required 53 | coordinates: CityCoordinates 54 | } 55 | 56 | // This structure is nested within GetCityOutput. 57 | structure CityCoordinates { 58 | @required 59 | latitude: Float 60 | 61 | @required 62 | longitude: Float 63 | } 64 | 65 | // "error" is a trait that is used to specialize 66 | // a structure as an error. 67 | @error("client") 68 | structure NoSuchResource { 69 | @required 70 | resourceType: String 71 | } 72 | 73 | // The paginated trait indicates that the operation may 74 | // return truncated results. 75 | @readonly 76 | @paginated(items: "items") 77 | operation ListCities { 78 | input: ListCitiesInput 79 | output: ListCitiesOutput 80 | } 81 | 82 | @input 83 | structure ListCitiesInput { 84 | nextToken: String 85 | pageSize: Integer 86 | } 87 | 88 | @output 89 | structure ListCitiesOutput { 90 | nextToken: String 91 | 92 | @required 93 | items: CitySummaries 94 | } 95 | 96 | // CitySummaries is a list of CitySummary structures. 97 | list CitySummaries { 98 | member: CitySummary 99 | } 100 | 101 | // CitySummary contains a reference to a City. 102 | @references([{resource: City}]) 103 | structure CitySummary { 104 | @required 105 | cityId: CityId 106 | 107 | @required 108 | name: String 109 | } 110 | 111 | @readonly 112 | operation GetCurrentTime { 113 | input: GetCurrentTimeInput 114 | output: GetCurrentTimeOutput 115 | } 116 | 117 | @input 118 | structure GetCurrentTimeInput {} 119 | 120 | @output 121 | structure GetCurrentTimeOutput { 122 | @required 123 | time: Timestamp 124 | } 125 | 126 | @readonly 127 | operation GetForecast { 128 | input: GetForecastInput 129 | output: GetForecastOutput 130 | } 131 | 132 | // "cityId" provides the only identifier for the resource since 133 | // a Forecast doesn't have its own. 134 | @input 135 | structure GetForecastInput { 136 | @required 137 | cityId: CityId 138 | } 139 | 140 | @output 141 | structure GetForecastOutput { 142 | chanceOfRain: Float 143 | } 144 | -------------------------------------------------------------------------------- /test-fixtures/suite3/smithy-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "sources": ["./main.smithy"], 4 | "maven": { 5 | "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], 6 | "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test-fixtures/suite4/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "smithyLsp.rootPath": "${workspaceRoot}/smithy", 3 | "smithyLsp.logToFile": "enabled" 4 | } 5 | -------------------------------------------------------------------------------- /test-fixtures/suite4/smithy/main.smithy: -------------------------------------------------------------------------------- 1 | $version: "2.0" 2 | 3 | namespace example.weather 4 | 5 | use aws.api#dataPlane 6 | use smithy.waiters#waitable 7 | 8 | /// Provides weather forecasts. 9 | service Weather { 10 | version: "2006-03-01" 11 | operations: [GetCurrentTime, GetWeatherReport] 12 | } 13 | 14 | @readonly 15 | @dataPlane 16 | operation GetCurrentTime { 17 | input := {} 18 | output := { 19 | @required 20 | time: Timestamp 21 | } 22 | } 23 | 24 | @waitable( 25 | ReportGenerated: { 26 | documentation: "Wait until the weather report is generated" 27 | acceptors: [ 28 | { 29 | state: "success" 30 | matcher: { 31 | success: true 32 | } 33 | } 34 | { 35 | state: "retry" 36 | matcher: { 37 | errorType: "NotFound" 38 | } 39 | } 40 | ] 41 | } 42 | ) 43 | operation GetWeatherReport { 44 | input := { 45 | @required 46 | cityId: String 47 | } 48 | output := { 49 | @required 50 | temperature: String 51 | } 52 | errors: [NotFound] 53 | } 54 | 55 | @error("client") 56 | structure NotFound { 57 | @required 58 | message: String 59 | } 60 | -------------------------------------------------------------------------------- /test-fixtures/suite4/smithy/smithy-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "sources": ["./main.smithy"], 4 | "maven": { 5 | "dependencies": [ 6 | "software.amazon.smithy:smithy-aws-traits:1.40.0", 7 | "software.amazon.smithy:smithy-waiters:1.40.0" 8 | ], 9 | "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test-fixtures/suite5/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "smithyLsp.rootPath": "${workspaceRoot}/smithy", 3 | } 4 | -------------------------------------------------------------------------------- /test-fixtures/suite5/smithy/main.smithy: -------------------------------------------------------------------------------- 1 | $version: "2.0" 2 | 3 | namespace example.weather 4 | 5 | /// Provides weather forecasts. 6 | service Weather { 7 | version: "2006-03-01" 8 | operations: [GetCurrentTime] 9 | } 10 | 11 | operation GetCurrentTime { 12 | // Below line to be indented. 13 | input := {} 14 | } 15 | -------------------------------------------------------------------------------- /test-fixtures/suite5/smithy/smithy-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "sources": ["./main.smithy"], 4 | "maven": { 5 | "dependencies": [ 6 | "software.amazon.smithy:smithy-aws-traits:1.40.0", 7 | "software.amazon.smithy:smithy-waiters:1.40.0" 8 | ], 9 | "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test-fixtures/suite6/smithy-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0" 3 | } 4 | -------------------------------------------------------------------------------- /tests/grammar/aggregate-shapes.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests aggregate shapes" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | list List { 7 | // <---- keyword.statement.smithy 8 | // ^^^^ entity.name.type.smithy 9 | // ^ punctuation.definition.dictionary.begin.smithy 10 | 11 | member: String 12 | // ^^^^^^ support.type.property-name.smithy 13 | // ^ punctuation.separator.dictionary.key-value.smithy 14 | // ^^^^^^ entity.name.type.smithy 15 | 16 | } 17 | // <- punctuation.definition.dictionary.end.smithy 18 | 19 | set Set { 20 | // <--- keyword.statement.smithy 21 | // ^^^ entity.name.type.smithy 22 | // ^ punctuation.definition.dictionary.begin.smithy 23 | 24 | member: String 25 | // ^^^^^^ support.type.property-name.smithy 26 | // ^ punctuation.separator.dictionary.key-value.smithy 27 | // ^^^^^^ entity.name.type.smithy 28 | 29 | } 30 | // <- punctuation.definition.dictionary.end.smithy 31 | 32 | map Map { 33 | // <--- keyword.statement.smithy 34 | // ^^^ entity.name.type.smithy 35 | // ^ punctuation.definition.dictionary.begin.smithy 36 | 37 | key: String 38 | // ^^^ support.type.property-name.smithy 39 | // ^ punctuation.separator.dictionary.key-value.smithy 40 | // ^^^^^^ entity.name.type.smithy 41 | 42 | value: String 43 | // ^^^^^ support.type.property-name.smithy 44 | // ^ punctuation.separator.dictionary.key-value.smithy 45 | // ^^^^^^ entity.name.type.smithy 46 | 47 | } 48 | // <- punctuation.definition.dictionary.end.smithy 49 | 50 | structure Structure { 51 | // <--------- keyword.statement.smithy 52 | // ^^^^^^^^^ entity.name.type.smithy 53 | // ^ punctuation.definition.dictionary.begin.smithy 54 | 55 | basic: String 56 | // ^^^^^ support.type.property-name.smithy 57 | // ^ punctuation.separator.dictionary.key-value.smithy 58 | // ^^^^^^ entity.name.type.smithy 59 | 60 | } 61 | // <- punctuation.definition.dictionary.end.smithy 62 | 63 | structure StructureWithDefaultTraitSugar { 64 | // <--------- keyword.statement.smithy 65 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy 66 | // ^ punctuation.definition.dictionary.begin.smithy 67 | 68 | normative: Boolean = true 69 | // ^^^^^^^^^ support.type.property-name.smithy 70 | // ^ punctuation.separator.dictionary.key-value.smithy 71 | // ^^^^^^^ entity.name.type.smithy 72 | // ^ keyword.operator.smithy 73 | // ^^^^ constant.language.smithy 74 | 75 | } 76 | // <- punctuation.definition.dictionary.end.smithy 77 | 78 | union Union { 79 | // <----- keyword.statement.smithy 80 | // ^^^^^ entity.name.type.smithy 81 | // ^ punctuation.definition.dictionary.begin.smithy 82 | 83 | foo: String 84 | // ^^^ support.type.property-name.smithy 85 | // ^ punctuation.separator.dictionary.key-value.smithy 86 | // ^^^^^^ entity.name.type.smithy 87 | 88 | } 89 | // <- punctuation.definition.dictionary.end.smithy -------------------------------------------------------------------------------- /tests/grammar/apply.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests apply statements" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | string Foo 7 | 8 | apply Foo @mixin 9 | // <----- keyword.statement.smithy 10 | // ^^^ entity.name.type.smithy 11 | // ^ punctuation.definition.annotation.smithy 12 | // ^^^^^ storage.type.annotation.smithy 13 | 14 | apply com.example#Foo @mixin 15 | // <----- keyword.statement.smithy 16 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 17 | // ^ punctuation.definition.annotation.smithy 18 | // ^^^^^ storage.type.annotation.smithy 19 | -------------------------------------------------------------------------------- /tests/grammar/control.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests control statments" 2 | 3 | $version: "2.0" 4 | // <- keyword.statement.control.smithy 5 | // <~------- support.type.property-name.smithy 6 | // ^ punctuation.separator.dictionary.pair.smithy 7 | // ^^^^^ string.quoted.double.smithy -------------------------------------------------------------------------------- /tests/grammar/enums.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests enum and intEnum shapes" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | enum Enum { 7 | // <---- keyword.statement.smithy 8 | // ^^^^ entity.name.type.smithy 9 | // ^ punctuation.definition.dictionary.begin.smithy 10 | 11 | @enumValue("member") 12 | // ^ punctuation.definition.annotation.smithy 13 | // ^^^^^^^^^ storage.type.annotation.smithy 14 | // ^ punctuation.definition.dictionary.begin.smithy 15 | // ^^^^^^^^ string.quoted.double.smithy 16 | // ^ punctuation.definition.dictionary.end.smithy 17 | 18 | MEMBER 19 | // ^^^^^^ entity.name.type.smithy 20 | 21 | } 22 | // <- punctuation.definition.dictionary.end.smithy 23 | 24 | enum EnumWithEnumValueTraitSugar { 25 | // <---- keyword.statement.smithy 26 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy 27 | // ^ punctuation.definition.dictionary.begin.smithy 28 | 29 | MEMBER = "member" 30 | // ^^^^^^ entity.name.type.smithy 31 | // ^ keyword.operator.smithy 32 | // ^^^^^^^^ string.quoted.double.smithy 33 | 34 | } 35 | // <- punctuation.definition.dictionary.end.smithy 36 | 37 | intEnum IntEnum { 38 | // <------- keyword.statement.smithy 39 | // ^^^^^^^ entity.name.type.smithy 40 | // ^ punctuation.definition.dictionary.begin.smithy 41 | 42 | @enumValue(1) 43 | // ^ punctuation.definition.annotation.smithy 44 | // ^^^^^^^^^ storage.type.annotation.smithy 45 | // ^ punctuation.definition.dictionary.begin.smithy 46 | // ^ constant.numeric.smithy 47 | // ^ punctuation.definition.dictionary.end.smithy 48 | 49 | MEMBER 50 | // ^^^^^^ entity.name.type.smithy 51 | 52 | } 53 | // <- punctuation.definition.dictionary.end.smithy 54 | 55 | intEnum IntEnumWithEnumValueTraitSugar { 56 | // <------- keyword.statement.smithy 57 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy 58 | // ^ punctuation.definition.dictionary.begin.smithy 59 | 60 | MEMBER = 1 61 | // ^^^^^^ entity.name.type.smithy 62 | // ^ keyword.operator.smithy 63 | // ^ constant.numeric.smithy 64 | 65 | } 66 | // <- punctuation.definition.dictionary.end.smithy 67 | -------------------------------------------------------------------------------- /tests/grammar/metadata.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests metadata statments" 2 | $version: "2.0" 3 | 4 | metadata foo = "bar" 5 | // <-------- keyword.statement.smithy 6 | // ^^^ variable.other.smithy 7 | // ^ keyword.operator.smithy 8 | // ^^^^^ string.quoted.double.smithy 9 | 10 | metadata "foo" = "bar" 11 | // ^^^^^ variable.other.smithy -------------------------------------------------------------------------------- /tests/grammar/mixins.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests using mixins on all shape types" 2 | $version: "2.0" 3 | 4 | namespace smithy.example 5 | 6 | @mixin 7 | blob MixinBlob 8 | 9 | blob MixedBlob with [MixinBlob] 10 | // <---- keyword.statement.smithy 11 | // ^^^^^^^^^ entity.name.type.smithy 12 | // ^^^^ keyword.statement.with.smithy 13 | // ^ punctuation.definition.array.begin.smithy 14 | // ^^^^^^^^^ entity.name.type.smithy 15 | // ^ punctuation.definition.array.end.smithy 16 | 17 | @mixin 18 | boolean MixinBoolean 19 | 20 | boolean MixedBoolean with [MixinBoolean] 21 | // <------- keyword.statement.smithy 22 | // ^^^^^^^^^^^^ entity.name.type.smithy 23 | // ^^^^ keyword.statement.with.smithy 24 | // ^ punctuation.definition.array.begin.smithy 25 | // ^^^^^^^^^^^^ entity.name.type.smithy 26 | // ^ punctuation.definition.array.end.smithy 27 | 28 | @mixin 29 | string MixinString 30 | 31 | string MixedString with [MixinString] 32 | // <------ keyword.statement.smithy 33 | // ^^^^^^^^^^^ entity.name.type.smithy 34 | // ^^^^ keyword.statement.with.smithy 35 | // ^ punctuation.definition.array.begin.smithy 36 | // ^^^^^^^^^^^ entity.name.type.smithy 37 | // ^ punctuation.definition.array.end.smithy 38 | 39 | @mixin 40 | byte MixinByte 41 | 42 | byte MixedByte with [MixinByte] 43 | // <---- keyword.statement.smithy 44 | // ^^^^^^^^^ entity.name.type.smithy 45 | // ^^^^ keyword.statement.with.smithy 46 | // ^ punctuation.definition.array.begin.smithy 47 | // ^^^^^^^^^ entity.name.type.smithy 48 | // ^ punctuation.definition.array.end.smithy 49 | 50 | @mixin 51 | short MixinShort 52 | 53 | short MixedShort with [MixinShort] 54 | // <----- keyword.statement.smithy 55 | // ^^^^^^^^^^ entity.name.type.smithy 56 | // ^^^^ keyword.statement.with.smithy 57 | // ^ punctuation.definition.array.begin.smithy 58 | // ^^^^^^^^^^ entity.name.type.smithy 59 | // ^ punctuation.definition.array.end.smithy 60 | 61 | @mixin 62 | integer MixinInteger 63 | 64 | integer MixedInteger with [MixinInteger] 65 | // <------- keyword.statement.smithy 66 | // ^^^^^^^^^ entity.name.type.smithy 67 | // ^^^^ keyword.statement.with.smithy 68 | // ^ punctuation.definition.array.begin.smithy 69 | // ^^^^^^^^^^^^ entity.name.type.smithy 70 | // ^ punctuation.definition.array.end.smithy 71 | 72 | @mixin 73 | long MixinLong 74 | 75 | long MixedLong with [MixinLong] 76 | // <---- keyword.statement.smithy 77 | // ^^^^^^^^^ entity.name.type.smithy 78 | // ^^^^ keyword.statement.with.smithy 79 | // ^ punctuation.definition.array.begin.smithy 80 | // ^^^^^^^^^ entity.name.type.smithy 81 | // ^ punctuation.definition.array.end.smithy 82 | 83 | @mixin 84 | float MixinFloat 85 | 86 | float MixedFloat with [MixinFloat] 87 | // <----- keyword.statement.smithy 88 | // ^^^^^^^^^^ entity.name.type.smithy 89 | // ^^^^ keyword.statement.with.smithy 90 | // ^ punctuation.definition.array.begin.smithy 91 | // ^^^^^^^^^^ entity.name.type.smithy 92 | // ^ punctuation.definition.array.end.smithy 93 | 94 | @mixin 95 | double MixinDouble 96 | 97 | double MixedDouble with [MixinDouble] 98 | // <------ keyword.statement.smithy 99 | // ^^^^^^^^^^^ entity.name.type.smithy 100 | // ^^^^ keyword.statement.with.smithy 101 | // ^ punctuation.definition.array.begin.smithy 102 | // ^^^^^^^^^^^ entity.name.type.smithy 103 | // ^ punctuation.definition.array.end.smithy 104 | 105 | @mixin 106 | bigInteger MixinBigInt 107 | 108 | bigInteger MixedBigInt with [MixinBigInt] 109 | // <---------- keyword.statement.smithy 110 | // ^^^^^^^^^^^ entity.name.type.smithy 111 | // ^^^^ keyword.statement.with.smithy 112 | // ^ punctuation.definition.array.begin.smithy 113 | // ^^^^^^^^^^^ entity.name.type.smithy 114 | // ^ punctuation.definition.array.end.smithy 115 | 116 | @mixin 117 | bigDecimal MixinBigDecimal 118 | 119 | bigDecimal MixedBigDecimal with [MixinBigDecimal] 120 | // <---------- keyword.statement.smithy 121 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 122 | // ^^^^ keyword.statement.with.smithy 123 | // ^ punctuation.definition.array.begin.smithy 124 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 125 | // ^ punctuation.definition.array.end.smithy 126 | 127 | @mixin 128 | timestamp MixinTimestamp 129 | 130 | timestamp MixedTimestamp with [MixinTimestamp] 131 | // <--------- keyword.statement.smithy 132 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 133 | // ^^^^ keyword.statement.with.smithy 134 | // ^ punctuation.definition.array.begin.smithy 135 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 136 | // ^ punctuation.definition.array.end.smithy 137 | 138 | @mixin 139 | document MixinDocument 140 | 141 | document MixedDocument with [MixinDocument] 142 | // <-------- keyword.statement.smithy 143 | // ^^^^^^^^^^^^^ entity.name.type.smithy 144 | // ^^^^ keyword.statement.with.smithy 145 | // ^ punctuation.definition.array.begin.smithy 146 | // ^^^^^^^^^^^^^ entity.name.type.smithy 147 | // ^ punctuation.definition.array.end.smithy 148 | 149 | 150 | list MixedList with [MixinList] {} 151 | // <---- keyword.statement.smithy 152 | // ^^^^^^^^^ entity.name.type.smithy 153 | // ^^^^ keyword.statement.with.smithy 154 | // ^ punctuation.definition.array.begin.smithy 155 | // ^^^^^^^^^ entity.name.type.smithy 156 | // ^ punctuation.definition.array.end.smithy 157 | // ^ punctuation.definition.dictionary.begin.smithy 158 | // ^ punctuation.definition.dictionary.end.smithy 159 | 160 | @mixin 161 | set MixinSet { 162 | member: String 163 | } 164 | 165 | set MixedSet with [MixinSet] {} 166 | // <--- keyword.statement.smithy 167 | // ^^^^^^^^ entity.name.type.smithy 168 | // ^^^^ keyword.statement.with.smithy 169 | // ^ punctuation.definition.array.begin.smithy 170 | // ^^^^^^^^ entity.name.type.smithy 171 | // ^ punctuation.definition.array.end.smithy 172 | // ^ punctuation.definition.dictionary.begin.smithy 173 | // ^ punctuation.definition.dictionary.end.smithy 174 | 175 | @mixin 176 | map MixinMap { 177 | key: String 178 | value: String 179 | } 180 | 181 | map MixedMap with [MixinMap] {} 182 | // <--- keyword.statement.smithy 183 | // ^^^^^^^^ entity.name.type.smithy 184 | // ^^^^ keyword.statement.with.smithy 185 | // ^ punctuation.definition.array.begin.smithy 186 | // ^^^^^^^^ entity.name.type.smithy 187 | // ^ punctuation.definition.array.end.smithy 188 | // ^ punctuation.definition.dictionary.begin.smithy 189 | // ^ punctuation.definition.dictionary.end.smithy 190 | 191 | @mixin 192 | structure MixinStructure {} 193 | 194 | structure MixedStructure with [MixinStructure] {} 195 | // <--------- keyword.statement.smithy 196 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 197 | // ^^^^ keyword.statement.with.smithy 198 | // ^ punctuation.definition.array.begin.smithy 199 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 200 | // ^ punctuation.definition.array.end.smithy 201 | // ^ punctuation.definition.dictionary.begin.smithy 202 | // ^ punctuation.definition.dictionary.end.smithy 203 | 204 | @mixin 205 | service MixinService {} 206 | 207 | service MixedService with [MixinService] {} 208 | // <------- keyword.statement.smithy 209 | // ^^^^^^^^^^^^ entity.name.type.smithy 210 | // ^^^^ keyword.statement.with.smithy 211 | // ^ punctuation.definition.array.begin.smithy 212 | // ^^^^^^^^^^^^ entity.name.type.smithy 213 | // ^ punctuation.definition.array.end.smithy 214 | // ^ punctuation.definition.dictionary.begin.smithy 215 | // ^ punctuation.definition.dictionary.end.smithy 216 | 217 | @mixin 218 | resource MixinResource {} 219 | 220 | resource MixedResource with [MixinResource] {} 221 | // <-------- keyword.statement.smithy 222 | // ^^^^^^^^^^^^^ entity.name.type.smithy 223 | // ^^^^ keyword.statement.with.smithy 224 | // ^ punctuation.definition.array.begin.smithy 225 | // ^^^^^^^^^^^^^ entity.name.type.smithy 226 | // ^ punctuation.definition.array.end.smithy 227 | // ^ punctuation.definition.dictionary.begin.smithy 228 | // ^ punctuation.definition.dictionary.end.smithy 229 | 230 | @mixin 231 | operation MixinOperation {} 232 | 233 | operation MixedOperation with [MixinOperation] {} 234 | // <--------- keyword.statement.smithy 235 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 236 | // ^^^^ keyword.statement.with.smithy 237 | // ^ punctuation.definition.array.begin.smithy 238 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 239 | // ^ punctuation.definition.array.end.smithy 240 | // ^ punctuation.definition.dictionary.begin.smithy 241 | // ^ punctuation.definition.dictionary.end.smithy 242 | 243 | @mixin 244 | operation MixinOperation2 {} 245 | 246 | operation MultiMixedOperation with [ 247 | // <--------- keyword.statement.smithy 248 | // ^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy 249 | // ^^^^ keyword.statement.with.smithy 250 | // ^ punctuation.definition.array.begin.smithy 251 | 252 | MixinOperation 253 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 254 | 255 | MixinOperation2 256 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 257 | 258 | ] {} 259 | // <- punctuation.definition.array.end.smithy 260 | // <~~- punctuation.definition.dictionary.begin.smithy 261 | // ^ punctuation.definition.dictionary.end.smithy 262 | 263 | operation MultiMixedOperation2 with [MixinOperation, MixinOperation2] {} 264 | // <--------- keyword.statement.smithy 265 | // ^^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy 266 | // ^^^^ keyword.statement.with.smithy 267 | // ^ punctuation.definition.array.begin.smithy 268 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 269 | // ^ punctuation.separator.array.smithy 270 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 271 | // ^ punctuation.definition.array.end.smithy 272 | // ^ punctuation.definition.dictionary.begin.smithy 273 | // ^ punctuation.definition.dictionary.end.smithy -------------------------------------------------------------------------------- /tests/grammar/namespace.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests the namespace section" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | // <--------- keyword.statement.smithy 6 | // ^^^^^^^^^^^ entity.name.type.smithy -------------------------------------------------------------------------------- /tests/grammar/service-shapes.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests service shapes" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | service Service { 7 | // <------- keyword.statement.smithy 8 | // ^^^^^^^ entity.name.type.smithy 9 | // ^ punctuation.definition.dictionary.begin.smithy 10 | 11 | version: "2020-02-02" 12 | // ^^^^^^^ support.type.property-name.smithy 13 | // ^ punctuation.separator.dictionary.key-value.smithy 14 | // ^^^^^^^^^^^^ string.quoted.double.smithy 15 | 16 | operations: [ 17 | // ^^^^^^^^^^ support.type.property-name.smithy 18 | // ^ punctuation.separator.dictionary.key-value.smithy 19 | // ^ punctuation.definition.array.begin.smithy 20 | 21 | Operation 22 | // ^^^^^^^^^ entity.name.type.smithy 23 | 24 | ] 25 | // ^ punctuation.definition.array.end.smithy 26 | 27 | resources: [ 28 | // ^^^^^^^^^ support.type.property-name.smithy 29 | // ^ punctuation.separator.dictionary.key-value.smithy 30 | // ^ punctuation.definition.array.begin.smithy 31 | 32 | Resource 33 | // ^^^^^^^^ entity.name.type.smithy 34 | 35 | ] 36 | // ^ punctuation.definition.array.end.smithy 37 | 38 | errors: [ 39 | // ^^^^^^ support.type.property-name.smithy 40 | // ^ punctuation.separator.dictionary.key-value.smithy 41 | // ^ punctuation.definition.array.begin.smithy 42 | 43 | Error 44 | // ^^^^^ entity.name.type.smithy 45 | 46 | ] 47 | // ^ punctuation.definition.array.end.smithy 48 | 49 | rename: { 50 | // ^^^^^^ support.type.property-name.smithy 51 | // ^ punctuation.separator.dictionary.key-value.smithy 52 | // ^ punctuation.definition.dictionary.begin.smithy 53 | 54 | Foo: "Bar" 55 | // ^^^ support.type.property-name.smithy 56 | // ^ punctuation.separator.dictionary.key-value.smithy 57 | // ^^^^^ string.quoted.double.smithy 58 | 59 | } 60 | // ^ punctuation.definition.dictionary.end.smithy 61 | 62 | } 63 | // <- punctuation.definition.dictionary.end.smithy 64 | 65 | operation Operation { 66 | // <--------- keyword.statement.smithy 67 | // ^^^^^^^^^ entity.name.type.smithy 68 | // ^ punctuation.definition.dictionary.begin.smithy 69 | 70 | input := { 71 | // ^^^^^ support.type.property-name.smithy 72 | // ^^ punctuation.separator.dictionary.inline-struct.smithy 73 | // ^ punctuation.definition.dictionary.begin.smithy 74 | 75 | foo: Bar 76 | // ^^^ support.type.property-name.smithy 77 | // ^ punctuation.separator.dictionary.key-value.smithy 78 | // ^^^ entity.name.type.smithy 79 | 80 | } 81 | // ^ punctuation.definition.dictionary.end.smithy 82 | 83 | output: OperationOutput 84 | // ^^^^^^ support.type.property-name.smithy 85 | // ^ punctuation.separator.dictionary.key-value.smithy 86 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 87 | 88 | errors: [ 89 | // ^^^^^^ support.type.property-name.smithy 90 | // ^ punctuation.separator.dictionary.key-value.smithy 91 | // ^ punctuation.definition.array.begin.smithy 92 | 93 | Error 94 | // ^^^^^ entity.name.type.smithy 95 | 96 | ] 97 | // ^ punctuation.definition.array.end.smithy 98 | 99 | } 100 | // <- punctuation.definition.dictionary.end.smithy 101 | 102 | operation OtherOperation { 103 | // <--------- keyword.statement.smithy 104 | // ^^^^^^^^^^^^^^ entity.name.type.smithy 105 | // ^ punctuation.definition.dictionary.begin.smithy 106 | 107 | input := with [Bar] {} 108 | // ^^^^^ support.type.property-name.smithy 109 | // ^^ punctuation.separator.dictionary.inline-struct.smithy 110 | // ^^^^ keyword.statement.with.smithy 111 | // ^ punctuation.definition.array.begin.smithy 112 | // ^^^ entity.name.type.smithy 113 | // ^ punctuation.definition.array.end.smithy 114 | // ^ punctuation.definition.dictionary.begin.smithy 115 | // ^ punctuation.definition.dictionary.end.smithy 116 | 117 | output := @sensitive {} 118 | // ^^^^^^ support.type.property-name.smithy 119 | // ^^ punctuation.separator.dictionary.inline-struct.smithy 120 | // ^ punctuation.definition.annotation.smithy 121 | // ^^^^^^^^^ storage.type.annotation.smithy 122 | // ^ punctuation.definition.dictionary.begin.smithy 123 | // ^ punctuation.definition.dictionary.end.smithy 124 | 125 | } 126 | // <- punctuation.definition.dictionary.end.smithy 127 | 128 | resource Resource { 129 | // <-------- keyword.statement.smithy 130 | // ^^^^^^^^ entity.name.type.smithy 131 | // ^ punctuation.definition.dictionary.begin.smithy 132 | 133 | properties: { 134 | // ^^^^^^^^^^ support.type.property-name.smithy 135 | // ^ punctuation.separator.dictionary.key-value.smithy 136 | // ^ punctuation.definition.dictionary.begin.smithy 137 | 138 | myProp: Float 139 | // ^^^^^^ support.type.property-name.smithy 140 | // ^ punctuation.separator.dictionary.key-value.smithy 141 | // ^^^^^ entity.name.type.smithy 142 | } 143 | // ^ punctuation.definition.dictionary.end.smithy 144 | 145 | identifiers: { 146 | // ^^^^^^^^^^^ support.type.property-name.smithy 147 | // ^ punctuation.separator.dictionary.key-value.smithy 148 | // ^ punctuation.definition.dictionary.begin.smithy 149 | 150 | "id": String 151 | // ^^^^ support.type.property-name.smithy 152 | // ^ punctuation.separator.dictionary.key-value.smithy 153 | // ^^^^^^ entity.name.type.smithy 154 | 155 | } 156 | // ^ punctuation.definition.dictionary.end.smithy 157 | 158 | create: Create 159 | // ^^^^^^ support.type.property-name.smithy 160 | // ^ punctuation.separator.dictionary.key-value.smithy 161 | // ^^^^^^ entity.name.type.smithy 162 | 163 | put: Put 164 | // ^^^ support.type.property-name.smithy 165 | // ^ punctuation.separator.dictionary.key-value.smithy 166 | // ^^^ entity.name.type.smithy 167 | 168 | read: Read 169 | // ^^^^ support.type.property-name.smithy 170 | // ^ punctuation.separator.dictionary.key-value.smithy 171 | // ^^^^ entity.name.type.smithy 172 | 173 | update: Update 174 | // ^^^^^^ support.type.property-name.smithy 175 | // ^ punctuation.separator.dictionary.key-value.smithy 176 | // ^^^^^^ entity.name.type.smithy 177 | 178 | delete: Delete 179 | // ^^^^^^ support.type.property-name.smithy 180 | // ^ punctuation.separator.dictionary.key-value.smithy 181 | // ^^^^^^ entity.name.type.smithy 182 | 183 | list: List 184 | // ^^^^ support.type.property-name.smithy 185 | // ^ punctuation.separator.dictionary.key-value.smithy 186 | // ^^^^ entity.name.type.smithy 187 | 188 | operations: [ 189 | // ^^^^^^^^^^ support.type.property-name.smithy 190 | // ^ punctuation.separator.dictionary.key-value.smithy 191 | // ^ punctuation.definition.array.begin.smithy 192 | 193 | Operation 194 | // ^^^^^^^^^ entity.name.type.smithy 195 | 196 | ] 197 | // ^ punctuation.definition.array.end.smithy 198 | 199 | collectionOperations: [ 200 | // ^^^^^^^^^^^^^^^^^^^^ support.type.property-name.smithy 201 | // ^ punctuation.separator.dictionary.key-value.smithy 202 | // ^ punctuation.definition.array.begin.smithy 203 | 204 | CollectionOperation 205 | // ^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy 206 | 207 | ] 208 | // ^ punctuation.definition.array.end.smithy 209 | 210 | resources: [ 211 | // ^^^^^^^^^ support.type.property-name.smithy 212 | // ^ punctuation.separator.dictionary.key-value.smithy 213 | // ^ punctuation.definition.array.begin.smithy 214 | 215 | SubResource 216 | // ^^^^^^^^^^^ entity.name.type.smithy 217 | 218 | ] 219 | // ^ punctuation.definition.array.end.smithy 220 | 221 | } 222 | // <- punctuation.definition.dictionary.end.smithy 223 | 224 | // The `for` syntax here determines which resource should be checked. 225 | structure ResourceDetails for Resource { 226 | // <--------- keyword.statement.smithy 227 | // ^^^^^^^^^^^^^^^ entity.name.type.smithy 228 | // ^^^ keyword.statement.for-resource.smithy 229 | // ^^^^^^^^ entity.name.type.smithy 230 | // ^ punctuation.definition.dictionary.begin.smithy 231 | $id 232 | // ^ keyword.statement.elision.smithy 233 | // ^^ support.type.property-name.smithy 234 | 235 | $myProp 236 | // ^ keyword.statement.elision.smithy 237 | // ^^^^^^ support.type.property-name.smithy 238 | 239 | address: String 240 | // ^^^^^^^ support.type.property-name.smithy 241 | // ^ punctuation.separator.dictionary.key-value.smithy 242 | // ^^^^^^ entity.name.type.smithy 243 | } 244 | // <- punctuation.definition.dictionary.end.smithy 245 | -------------------------------------------------------------------------------- /tests/grammar/simple-shapes.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests simple shapes" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | blob Blob 7 | // <---- keyword.statement.smithy 8 | // ^^^^ entity.name.type.smithy 9 | 10 | boolean Bool 11 | // <------- keyword.statement.smithy 12 | // ^^^^ entity.name.type.smithy 13 | 14 | string String 15 | // <------ keyword.statement.smithy 16 | // ^^^^^^ entity.name.type.smithy 17 | 18 | byte Byte 19 | // <---- keyword.statement.smithy 20 | // ^^^^ entity.name.type.smithy 21 | 22 | short Short 23 | // <----- keyword.statement.smithy 24 | // ^^^^^ entity.name.type.smithy 25 | 26 | integer Integer 27 | // <------- keyword.statement.smithy 28 | // ^^^^^^^ entity.name.type.smithy 29 | 30 | long Long 31 | // <---- keyword.statement.smithy 32 | // ^^^^ entity.name.type.smithy 33 | 34 | float Float 35 | // <----- keyword.statement.smithy 36 | // ^^^^^ entity.name.type.smithy 37 | 38 | double Double 39 | // <------ keyword.statement.smithy 40 | // ^^^^^^ entity.name.type.smithy 41 | 42 | bigInteger BigInt 43 | // <---------- keyword.statement.smithy 44 | // ^^^^^^ entity.name.type.smithy 45 | 46 | bigDecimal BigDecimal 47 | // <---------- keyword.statement.smithy 48 | // ^^^^^^^^^^ entity.name.type.smithy 49 | 50 | timestamp Timestamp 51 | // <--------- keyword.statement.smithy 52 | // ^^^^^^^^^ entity.name.type.smithy 53 | 54 | document Document 55 | // <-------- keyword.statement.smithy 56 | // ^^^^^^^^ entity.name.type.smithy -------------------------------------------------------------------------------- /tests/grammar/target-elision.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests target elision" 2 | $version: "2.0" 3 | 4 | namespace smithy.example 5 | 6 | resource User { 7 | identifiers: { 8 | uuid: String 9 | } 10 | } 11 | 12 | @mixin 13 | structure UserMixin { 14 | uuid: String 15 | } 16 | 17 | structure UserStructWithResource for User { 18 | // ^^^ keyword.statement.for-resource.smithy 19 | // ^^^^ entity.name.type.smithy 20 | 21 | $uuid 22 | // ^ keyword.statement.elision.smithy 23 | // ^^^^ support.type.property-name.smithy 24 | } 25 | 26 | structure UserStructWithMixin with [UserMixin] { 27 | $name 28 | // ^ keyword.statement.elision.smithy 29 | // ^^^^ support.type.property-name.smithy 30 | } 31 | 32 | structure UserStructWithResourceAndMixin for User with [UserMixin] { 33 | // ^^^ keyword.statement.for-resource.smithy 34 | // ^^^^ entity.name.type.smithy 35 | // ^^^^ keyword.statement.with.smithy 36 | // ^ punctuation.definition.array.begin.smithy 37 | // ^^^^^^^^^ entity.name.type.smithy 38 | // ^ punctuation.definition.array.end.smithy 39 | 40 | $uuid 41 | // ^ keyword.statement.elision.smithy 42 | // ^^^^ support.type.property-name.smithy 43 | 44 | $name 45 | // ^ keyword.statement.elision.smithy 46 | // ^^^^ support.type.property-name.smithy 47 | } 48 | -------------------------------------------------------------------------------- /tests/grammar/traits.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests traits" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | @foo 7 | // <- punctuation.definition.annotation.smithy 8 | // <~--- storage.type.annotation.smithy 9 | 10 | @bar() 11 | // <- punctuation.definition.annotation.smithy 12 | // <~--- storage.type.annotation.smithy 13 | // ^ punctuation.definition.dictionary.begin.smithy 14 | // ^ punctuation.definition.dictionary.end.smithy 15 | 16 | @baz(400) 17 | // <- punctuation.definition.annotation.smithy 18 | // <~--- storage.type.annotation.smithy 19 | // ^ punctuation.definition.dictionary.begin.smithy 20 | // ^^^ constant.numeric.smithy 21 | // ^ punctuation.definition.dictionary.end.smithy 22 | 23 | string Foo 24 | 25 | apply Foo @mixin 26 | // <----- keyword.statement.smithy 27 | // ^^^ entity.name.type.smithy 28 | // ^ punctuation.definition.annotation.smithy 29 | // ^^^^^ storage.type.annotation.smithy -------------------------------------------------------------------------------- /tests/grammar/use.smithy: -------------------------------------------------------------------------------- 1 | // SYNTAX TEST "source.smithy" "This tests the use section" 2 | $version: "2.0" 3 | 4 | namespace com.example 5 | 6 | use com.example.foo#Bar 7 | // <--- keyword.statement.smithy 8 | // ^^^^^^^^^^^^^^^^^^^ entity.name.type.smithy -------------------------------------------------------------------------------- /tests/helper.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, TextEditor, Uri } from 'vscode'; 2 | import { resolve } from 'path'; 3 | import { glob } from 'glob'; 4 | import * as Mocha from 'mocha'; 5 | 6 | export let doc: TextDocument; 7 | export let editor: TextEditor; 8 | 9 | export const getDocPath = (p: string) => { 10 | return resolve(__dirname, '../../test-fixtures', p); 11 | }; 12 | 13 | export const getDocUri = (p: string) => { 14 | return Uri.file(getDocPath(p)); 15 | }; 16 | 17 | export async function waitForServerStartup() { 18 | // Wait for Smithy Language Server to start 19 | await new Promise((resolve) => setTimeout(resolve, 9000)); 20 | } 21 | 22 | export function runTests(testsRoot: string, cb: (error: any, failures?: number) => void): void { 23 | const mocha = new Mocha({ 24 | ui: 'tdd', 25 | }); 26 | 27 | glob('**/**.test.js', { cwd: testsRoot }) 28 | .then((files) => { 29 | files.forEach((f) => mocha.addFile(resolve(testsRoot, f))); 30 | 31 | try { 32 | mocha.run((failures) => { 33 | cb(null, failures); 34 | }); 35 | } catch (err) { 36 | console.error(err); 37 | cb(err); 38 | } 39 | }) 40 | .catch((err) => { 41 | return cb(err); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /tests/runTest.ts: -------------------------------------------------------------------------------- 1 | import { spawnSync } from 'child_process'; 2 | import { resolve } from 'path'; 3 | 4 | import { 5 | runTests, 6 | downloadAndUnzipVSCode, 7 | resolveCliPathFromVSCodeExecutablePath, 8 | resolveCliArgsFromVSCodeExecutablePath, 9 | } from '@vscode/test-electron'; 10 | import * as assert from 'assert'; 11 | 12 | async function go() { 13 | try { 14 | const extensionDevelopmentPath = resolve(__dirname, '../../'); 15 | 16 | // Suite 1 - Extension registration and launching language server 17 | await runTests({ 18 | extensionDevelopmentPath, 19 | extensionTestsPath: resolve(__dirname, './suite1'), 20 | launchArgs: [resolve(__dirname, '../../test-fixtures/suite1')], 21 | }); 22 | 23 | // Suite 2 - Diagnostics from broken model 24 | await runTests({ 25 | extensionDevelopmentPath, 26 | extensionTestsPath: resolve(__dirname, './suite2'), 27 | launchArgs: [resolve(__dirname, '../../test-fixtures/suite2')], 28 | }); 29 | 30 | // Suite 3 - Selector commands 31 | await runTests({ 32 | extensionDevelopmentPath, 33 | extensionTestsPath: resolve(__dirname, './suite3'), 34 | launchArgs: [resolve(__dirname, '../../test-fixtures/suite3')], 35 | }); 36 | 37 | // Suite 4 - User-specific root 38 | await runTests({ 39 | extensionDevelopmentPath, 40 | extensionTestsPath: resolve(__dirname, './suite4'), 41 | launchArgs: [resolve(__dirname, '../../test-fixtures/suite4')], 42 | }); 43 | 44 | // Suite 5 - Formatter 45 | await runTests({ 46 | extensionDevelopmentPath, 47 | extensionTestsPath: resolve(__dirname, './suite5'), 48 | launchArgs: [resolve(__dirname, '../../test-fixtures/suite5')], 49 | }); 50 | 51 | // Suite 6 - Startup 52 | await runTests({ 53 | extensionDevelopmentPath, 54 | extensionTestsPath: resolve(__dirname, './suite6'), 55 | launchArgs: [resolve(__dirname, '../../test-fixtures/suite6')], 56 | }); 57 | 58 | // Confirm that webpacked and vsce packaged extension can be installed. 59 | const vscodeExecutablePath = await downloadAndUnzipVSCode(); 60 | const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); 61 | 62 | const result = spawnSync(cli, [...args, '--install-extension', 'smithy-vscode.vsix', '--force'], { 63 | encoding: 'utf-8', 64 | }); 65 | assert.equal(result.status, 0); 66 | assert.match(result.stdout, /Extension 'smithy-vscode.vsix' was successfully installed./); 67 | } catch (err) { 68 | console.error('Test Failure'); 69 | console.log(err); 70 | process.exit(1); 71 | } 72 | } 73 | 74 | go(); 75 | -------------------------------------------------------------------------------- /tests/suite1/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import { getDocUri, waitForServerStartup } from './../helper'; 4 | 5 | suite('Extension tests', function () { 6 | this.timeout(0); 7 | 8 | test('Should start extension and Language Server', async () => { 9 | const smithyMainUri = getDocUri('suite1/main.smithy'); 10 | const doc = await vscode.workspace.openTextDocument(smithyMainUri); 11 | const editor = await vscode.window.showTextDocument(doc); 12 | const ext = vscode.extensions.getExtension('smithy.smithy-vscode-extension'); 13 | await waitForServerStartup(); 14 | const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); 15 | 16 | // Grab model file directly 17 | const modelFile = await vscode.workspace.openTextDocument(getDocUri('suite1/main.smithy')); 18 | const modelFileText = modelFile.getText(); 19 | 20 | assert.match(modelFileText, /namespace example.weather/); 21 | 22 | assert.notEqual(doc, undefined); 23 | assert.notEqual(editor, undefined); 24 | assert.equal(ext.isActive, true); 25 | assert.deepStrictEqual(diagnostics, []); 26 | }); 27 | 28 | test('Should register language', async () => { 29 | const languages = await vscode.languages.getLanguages(); 30 | assert.equal(languages.includes('smithy'), true); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /tests/suite1/index.ts: -------------------------------------------------------------------------------- 1 | import { runTests } from '../helper'; 2 | 3 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 4 | runTests(testsRoot, cb); 5 | } 6 | -------------------------------------------------------------------------------- /tests/suite2/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import { getDocUri, waitForServerStartup } from './../helper'; 4 | 5 | suite('broken model tests', function () { 6 | this.timeout(0); 7 | 8 | test('Should provide diagnostics', async () => { 9 | const smithyMainUri = getDocUri('suite2/main.smithy'); 10 | const doc = await vscode.workspace.openTextDocument(smithyMainUri); 11 | await vscode.window.showTextDocument(doc); 12 | await waitForServerStartup(); 13 | const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); 14 | 15 | assert.match(diagnostics[0].message, /Cannot apply `smithy.api#deprecated` to an immutable prelude shape/); 16 | assert.equal(diagnostics[0].range.start.line, 4); 17 | assert.equal(diagnostics[0].range.start.character, 24); 18 | return Promise.resolve(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/suite2/index.ts: -------------------------------------------------------------------------------- 1 | import { runTests } from '../helper'; 2 | 3 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 4 | runTests(testsRoot, cb); 5 | } 6 | -------------------------------------------------------------------------------- /tests/suite3/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { getDocUri, waitForServerStartup } from './../helper'; 3 | import * as sinon from 'sinon'; 4 | 5 | suite('Selector tests', function () { 6 | this.timeout(0); 7 | 8 | test('Can run selectors', async () => { 9 | const smithyMainUri = getDocUri('suite3/main.smithy'); 10 | const doc = await vscode.workspace.openTextDocument(smithyMainUri); 11 | await vscode.window.showTextDocument(doc); 12 | await waitForServerStartup(); 13 | 14 | const showInputBox = sinon.stub(vscode.window, 'showInputBox'); 15 | showInputBox.resolves('operation [id|namespace=example.weather]'); 16 | await vscode.commands.executeCommand('smithy.runSelector'); 17 | // we don't have a way to check the output. as long as this command 18 | // can run it should be fine - more robust tests are done on the server 19 | // side. 20 | return Promise.resolve(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /tests/suite3/index.ts: -------------------------------------------------------------------------------- 1 | import { runTests } from '../helper'; 2 | 3 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 4 | runTests(testsRoot, cb); 5 | } 6 | -------------------------------------------------------------------------------- /tests/suite4/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import { getDocUri, waitForServerStartup } from '../helper'; 4 | 5 | suite('User-specific root', function () { 6 | this.timeout(0); 7 | 8 | test('Should download jars even when not in workspace root', async () => { 9 | const smithyMainUri = getDocUri('suite4/smithy/main.smithy'); 10 | const doc = await vscode.workspace.openTextDocument(smithyMainUri); 11 | await vscode.window.showTextDocument(doc); 12 | await waitForServerStartup(); 13 | const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); 14 | 15 | // We would have diagnostics for unknown traits if the jars weren't downloaded 16 | assert.equal(diagnostics.length, 0); 17 | return Promise.resolve(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/suite4/index.ts: -------------------------------------------------------------------------------- 1 | import { runTests } from '../helper'; 2 | 3 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 4 | runTests(testsRoot, cb); 5 | } 6 | -------------------------------------------------------------------------------- /tests/suite5/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import { getDocUri, waitForServerStartup } from '../helper'; 4 | 5 | suite('formatting tests', function () { 6 | this.timeout(0); 7 | 8 | test('Should register Smithy formatter', async () => { 9 | const smithyMainUri = getDocUri('suite5/smithy/main.smithy'); 10 | const doc = await vscode.workspace.openTextDocument(smithyMainUri); 11 | await vscode.window.showTextDocument(doc); 12 | await waitForServerStartup(); 13 | 14 | const beforeEditText = doc.getText(); 15 | await vscode.commands.executeCommand('editor.action.formatDocument', smithyMainUri); 16 | const afterEditText = doc.getText(); 17 | assert.notStrictEqual(afterEditText, beforeEditText); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/suite5/index.ts: -------------------------------------------------------------------------------- 1 | import { runTests } from '../helper'; 2 | 3 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 4 | runTests(testsRoot, cb); 5 | } 6 | -------------------------------------------------------------------------------- /tests/suite6/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | 4 | suite('Startup', function () { 5 | this.timeout(0); 6 | 7 | test('Should start without opening a smithy file', async () => { 8 | const extension = vscode.extensions.getExtension('smithy.smithy-vscode-extension'); 9 | assert.ok(extension.isActive); 10 | 11 | return Promise.resolve(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/suite6/index.ts: -------------------------------------------------------------------------------- 1 | import { runTests } from '../helper'; 2 | 3 | export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { 4 | runTests(testsRoot, cb); 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2019", 5 | "outDir": "out", 6 | "lib": ["ES2019"], 7 | "sourceMap": true, 8 | "skipLibCheck": true 9 | }, 10 | "include": ["src", "tests"], 11 | "exclude": ["node_modules", ".vscode-test"] 12 | } 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', 10 | mode: 'none', // Set to 'production' when packaging 11 | 12 | entry: './src/extension.ts', 13 | output: { 14 | path: path.resolve(__dirname, 'out', 'src'), 15 | filename: 'extension.js', 16 | libraryTarget: 'commonjs2', 17 | }, 18 | devtool: 'nosources-source-map', 19 | externals: { 20 | vscode: 'commonjs vscode', // vscode module provided by VS Code itself. 21 | }, 22 | resolve: { 23 | extensions: ['.ts', '.js'], 24 | }, 25 | module: { 26 | rules: [ 27 | { 28 | test: /\.ts$/, 29 | exclude: /node_modules/, 30 | use: [ 31 | { 32 | loader: 'ts-loader', 33 | }, 34 | ], 35 | }, 36 | ], 37 | }, 38 | }; 39 | module.exports = config; 40 | --------------------------------------------------------------------------------