diff --git a/.prettierignore b/.prettierignore index bb5e894..363e0ea 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,3 +4,4 @@ build/ .vscode/ .vscode-test/ test-fixtures/**/build +package-lock.json diff --git a/language-configuration.json b/language-configuration.json index 1451c52..0dd54bc 100644 --- a/language-configuration.json +++ b/language-configuration.json @@ -1,27 +1,27 @@ { - "comments": { - "lineComment": "//" - }, - // symbols used as brackets - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - // symbols that are auto closed when typing - "autoClosingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"\"\"", "\"\"\""], - ["\"", "\""] - ], - // symbols that that can be used to surround a selection - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"\"\"", "\"\"\""], - ["\"", "\""] - ] + "comments": { + "lineComment": "//" + }, + // symbols used as brackets + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"\"\"", "\"\"\""], + ["\"", "\""] + ], + // symbols that that can be used to surround a selection + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"\"\"", "\"\"\""], + ["\"", "\""] + ] } diff --git a/package.json b/package.json index 48880c3..6be6b85 100644 --- a/package.json +++ b/package.json @@ -1,173 +1,175 @@ { - "name": "smithy-vscode-extension", - "displayName": "Smithy", - "description": "Smithy IDL Language Extension", - "version": "0.8.0", - "icon": "images/smithy_anvil_red.png", - "publisher": "smithy", - "engines": { - "vscode": "^1.84.1" - }, - "repository": { - "type": "git", - "url": "https://github.com/smithy-lang/smithy-vscode.git" - }, - "license": "Apache-2.0", - "prettier": { - "printWidth": 120 - }, - "categories": [ - "Programming Languages", - "Snippets" - ], - "main": "./out/src/extension", - "preview": true, - "activationEvents": [ - "workspaceContains:**/smithy-build.json", - "workspaceContains:**/*.smithy", - "workspaceContains:**/.smithy-project.json" - ], - "contributes": { - "languages": [ - { - "id": "smithy", - "aliases": [ - "Smithy", - "smithy" - ], - "extensions": [ - ".smithy" - ], - "icon": { - "dark": "./images/smithy_anvil_red_file_icon.png", - "light": "./images/smithy_anvil_red_file_icon.png" - }, - "configuration": "./language-configuration.json" - } - ], - "grammars": [ - { - "language": "smithy", - "scopeName": "source.smithy", - "path": "./syntaxes/smithy.tmLanguage.json" - } - ], - "snippets": [ - { - "language": "smithy", - "path": "./snippets.json" - } + "name": "smithy-vscode-extension", + "displayName": "Smithy", + "description": "Smithy IDL Language Extension", + "version": "0.8.0", + "icon": "images/smithy_anvil_red.png", + "publisher": "smithy", + "engines": { + "vscode": "^1.84.1" + }, + "repository": { + "type": "git", + "url": "https://github.com/smithy-lang/smithy-vscode.git" + }, + "license": "Apache-2.0", + "prettier": { + "tabWidth": 4, + "singleQuote": true, + "printWidth": 120 + }, + "categories": [ + "Programming Languages", + "Snippets" ], - "commands": [ - { - "command": "smithy.runSelector", - "title": "Smithy:Selector:Run" - }, - { - "command": "smithy.clearSelector", - "title": "Smithy:Selector:Clear" - } + "main": "./out/src/extension", + "preview": true, + "activationEvents": [ + "workspaceContains:**/smithy-build.json", + "workspaceContains:**/*.smithy", + "workspaceContains:**/.smithy-project.json" ], - "menus": { - "commandPalette": [ - { - "command": "smithy.runSelector", - "when": "editorLangId == smithy" + "contributes": { + "languages": [ + { + "id": "smithy", + "aliases": [ + "Smithy", + "smithy" + ], + "extensions": [ + ".smithy" + ], + "icon": { + "dark": "./images/smithy_anvil_red_file_icon.png", + "light": "./images/smithy_anvil_red_file_icon.png" + }, + "configuration": "./language-configuration.json" + } + ], + "grammars": [ + { + "language": "smithy", + "scopeName": "source.smithy", + "path": "./syntaxes/smithy.tmLanguage.json" + } + ], + "snippets": [ + { + "language": "smithy", + "path": "./snippets.json" + } + ], + "commands": [ + { + "command": "smithy.runSelector", + "title": "Smithy:Selector:Run" + }, + { + "command": "smithy.clearSelector", + "title": "Smithy:Selector:Clear" + } + ], + "menus": { + "commandPalette": [ + { + "command": "smithy.runSelector", + "when": "editorLangId == smithy" + }, + { + "command": "smithy.clearSelector", + "when": "editorLangId == smithy" + } + ] }, - { - "command": "smithy.clearSelector", - "when": "editorLangId == smithy" + "configuration": { + "type": "object", + "title": "vscode-smithy configuration", + "properties": { + "smithyLsp.maxNumberOfProblems": { + "scope": "resource", + "type": "number", + "default": 100, + "description": "Controls the maximum number of problems produced by the server." + }, + "smithyLsp.trace.server": { + "scope": "window", + "type": "string", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "verbose", + "description": "Traces the communication between VS Code and the language server." + }, + "smithyLsp.version": { + "scope": "window", + "type": "string", + "default": "0.6.0", + "description": "Version of the Smithy Language Server (see https://github.com/smithy-lang/smithy-language-server)." + }, + "smithyLsp.rootPath": { + "scope": "resource", + "type": "string" + }, + "smithyLsp.diagnostics.minimumSeverity": { + "scope": "window", + "type": "string", + "enum": [ + "NOTE", + "WARNING", + "DANGER", + "ERROR" + ], + "default": "WARNING", + "description": "Minimum severity of Smithy validation events to display in the editor." + }, + "smithyLsp.onlyReloadOnSave": { + "scope": "window", + "type": "boolean", + "default": false, + "description": "Whether to only re-load the Smithy model on save. Use this if the server feels slow as you type." + } + } } - ] }, - "configuration": { - "type": "object", - "title": "vscode-smithy configuration", - "properties": { - "smithyLsp.maxNumberOfProblems": { - "scope": "resource", - "type": "number", - "default": 100, - "description": "Controls the maximum number of problems produced by the server." - }, - "smithyLsp.trace.server": { - "scope": "window", - "type": "string", - "enum": [ - "off", - "messages", - "verbose" - ], - "default": "verbose", - "description": "Traces the communication between VS Code and the language server." - }, - "smithyLsp.version": { - "scope": "window", - "type": "string", - "default": "0.6.0", - "description": "Version of the Smithy Language Server (see https://github.com/smithy-lang/smithy-language-server)." - }, - "smithyLsp.rootPath": { - "scope": "resource", - "type": "string" - }, - "smithyLsp.diagnostics.minimumSeverity": { - "scope": "window", - "type": "string", - "enum": [ - "NOTE", - "WARNING", - "DANGER", - "ERROR" - ], - "default": "WARNING", - "description": "Minimum severity of Smithy validation events to display in the editor." - }, - "smithyLsp.onlyReloadOnSave": { - "scope": "window", - "type": "boolean", - "default": false, - "description": "Whether to only re-load the Smithy model on save. Use this if the server feels slow as you type." - } - } + "scripts": { + "vscode:prepublish": "npm run webpack-package", + "webpack-package": "webpack --mode production --devtool hidden-source-map", + "compile": "tsc -p ./", + "install-plugin": "npm run package && code --install-extension smithy-vscode.vsix", + "uninstall-plugin": "code --uninstall-extension smithy.smithy-vscode-extension", + "package": "vsce package -o smithy-vscode.vsix", + "format": "prettier --write '**/*.{ts,js,json}'", + "format-check": "prettier --check '**/*.{ts,js,json}'", + "test-grammar": "npx vscode-tmgrammar-test -g syntaxes/smithy.tmLanguage.json 'tests/grammar/*'", + "test-extension": "npm run compile && npm run package && node ./out/tests/runTest.js", + "test": "npm run format-check && npm run test-grammar && npm run test-extension" + }, + "devDependencies": { + "@types/follow-redirects": "^1.14.4", + "@types/glob": "^8.1.0", + "@types/mocha": "^10.0.4", + "@types/node": "^18.18.9", + "@types/sinon": "^10.0.20", + "@types/vscode": "^1.84.1", + "@vscode/test-electron": "^2.4.0", + "@vscode/vsce": "^2.22.0", + "glob": "^9.3.5", + "mocha": "^10.8.2", + "prettier": "^2.8.8", + "sinon": "^15.2.0", + "ts-loader": "^9.5.0", + "typescript": "^5.2.2", + "vscode-nls-dev": "^4.0.4", + "vscode-tmgrammar-test": "^0.1.2", + "webpack": "^5.94.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "follow-redirects": "^1.15.6", + "vscode-languageclient": "^8.1.0", + "vscode-nls": "^5.2.0" } - }, - "scripts": { - "vscode:prepublish": "npm run webpack-package", - "webpack-package": "webpack --mode production --devtool hidden-source-map", - "compile": "tsc -p ./", - "install-plugin": "npm run package && code --install-extension smithy-vscode.vsix", - "uninstall-plugin": "code --uninstall-extension smithy.smithy-vscode-extension", - "package": "vsce package -o smithy-vscode.vsix", - "format": "prettier --write '**/*.{ts,js,json,yml}'", - "format-check": "prettier --check '**/*.{ts,js,json,yml}'", - "test-grammar": "npx vscode-tmgrammar-test -g syntaxes/smithy.tmLanguage.json 'tests/grammar/*'", - "test-extension": "npm run compile && npm run package && node ./out/tests/runTest.js", - "test": "npm run format-check && npm run test-grammar && npm run test-extension" - }, - "devDependencies": { - "@types/follow-redirects": "^1.14.4", - "@types/glob": "^8.1.0", - "@types/mocha": "^10.0.4", - "@types/node": "^18.18.9", - "@types/sinon": "^10.0.20", - "@types/vscode": "^1.84.1", - "@vscode/test-electron": "^2.4.0", - "@vscode/vsce": "^2.22.0", - "glob": "^9.3.5", - "mocha": "^10.8.2", - "prettier": "^2.8.8", - "sinon": "^15.2.0", - "ts-loader": "^9.5.0", - "typescript": "^5.2.2", - "vscode-nls-dev": "^4.0.4", - "vscode-tmgrammar-test": "^0.1.2", - "webpack": "^5.94.0", - "webpack-cli": "^5.1.4" - }, - "dependencies": { - "follow-redirects": "^1.15.6", - "vscode-languageclient": "^8.1.0", - "vscode-nls": "^5.2.0" - } } diff --git a/snippets.json b/snippets.json index 1f0be0e..feed162 100644 --- a/snippets.json +++ b/snippets.json @@ -1,67 +1,67 @@ { - "Add Service": { - "prefix": "service", - "body": "service ${1:MyService} {\n version: \"${2:MyVersion}\"\n operations: [${3:MyOperation}]\n resources: [${4:MyResource}]\n errors: [${0:MyError}]\n}", - "description": "Adds a service with version, operations, resources and errors properties" - }, - "Add Resource based Service": { - "prefix": "service", - "body": "service ${1:MyService} {\n version: \"${2:version}\"\n resources: [${3:MyResource}]\n errors: [${0:MyError}]\n}", - "description": "Adds a service with version, resources and errors properties" - }, - "Add Operation based Service": { - "prefix": "service", - "body": "service ${1:MyService} {\n version: \"${2:MyVersion}\"\n operations: [${3:MyOperation}]\n errors: [${0:MyError}]\n}", - "description": "Adds a service with version, operations and errors properties" - }, - "Add Operation": { - "prefix": "operation", - "body": "operation ${1:MyOperation} {\n input: ${2:MyInput}\n output: ${3:MyOutput}\n errors: [${0:MyError}]\n}", - "description": "Adds an operation with input, output and errors properties" - }, - "Add lifecycle Resource": { - "prefix": "resource", - "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}", - "description": "Adds a resource with identifiers and lifecycle operations" - }, - "Add identifier only Resource": { - "prefix": "resource", - "body": "resource ${1:MyResource} {\n identifiers: { ${2:myIdentifierKey1}: ${0:MyIdentifierString} }\n}", - "description": "Adds a resource with identifiers only" - }, - "Add List shape": { - "prefix": "list", - "body": "list ${1:MyList} {\n member: ${0:MyListMember}\n}", - "description": "Adds a list shape" - }, - "Add Set shape": { - "prefix": "set", - "body": "set ${1:MySet} {\n member: ${0:MySetMember}\n}", - "description": "Adds a set shape" - }, - "Add Map shape": { - "prefix": "map", - "body": "map ${1:MyMap} {\n key: ${2:MyStringKey}\n value: ${0:MyValue}\n}", - "description": "Adds a map shape" - }, - "Add Structure shape": { - "prefix": "structure", - "body": "structure ${0:MyStructure} {\n}", - "description": "Adds a structure shape" - }, - "Add @input Structure shape": { - "prefix": "@input", - "body": "@input\nstructure ${1:MyStructure} {$0}", - "description": "Adds a structure shape with the @input trait" - }, - "Add @output Structure shape": { - "prefix": "@output", - "body": "@output\nstructure ${1:MyStructure} {$0}", - "description": "Adds a structure shape with the @output trait" - }, - "Add Union shape": { - "prefix": "union", - "body": "union ${1:myUnion} {\n ${2:myVariantA}: ${3:MyVariantTargetA}\n ${4:myVariantB}: ${0:MyVariantTargetB}\n}", - "description": "Adds a union shape" - } + "Add Service": { + "prefix": "service", + "body": "service ${1:MyService} {\n version: \"${2:MyVersion}\"\n operations: [${3:MyOperation}]\n resources: [${4:MyResource}]\n errors: [${0:MyError}]\n}", + "description": "Adds a service with version, operations, resources and errors properties" + }, + "Add Resource based Service": { + "prefix": "service", + "body": "service ${1:MyService} {\n version: \"${2:version}\"\n resources: [${3:MyResource}]\n errors: [${0:MyError}]\n}", + "description": "Adds a service with version, resources and errors properties" + }, + "Add Operation based Service": { + "prefix": "service", + "body": "service ${1:MyService} {\n version: \"${2:MyVersion}\"\n operations: [${3:MyOperation}]\n errors: [${0:MyError}]\n}", + "description": "Adds a service with version, operations and errors properties" + }, + "Add Operation": { + "prefix": "operation", + "body": "operation ${1:MyOperation} {\n input: ${2:MyInput}\n output: ${3:MyOutput}\n errors: [${0:MyError}]\n}", + "description": "Adds an operation with input, output and errors properties" + }, + "Add lifecycle Resource": { + "prefix": "resource", + "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}", + "description": "Adds a resource with identifiers and lifecycle operations" + }, + "Add identifier only Resource": { + "prefix": "resource", + "body": "resource ${1:MyResource} {\n identifiers: { ${2:myIdentifierKey1}: ${0:MyIdentifierString} }\n}", + "description": "Adds a resource with identifiers only" + }, + "Add List shape": { + "prefix": "list", + "body": "list ${1:MyList} {\n member: ${0:MyListMember}\n}", + "description": "Adds a list shape" + }, + "Add Set shape": { + "prefix": "set", + "body": "set ${1:MySet} {\n member: ${0:MySetMember}\n}", + "description": "Adds a set shape" + }, + "Add Map shape": { + "prefix": "map", + "body": "map ${1:MyMap} {\n key: ${2:MyStringKey}\n value: ${0:MyValue}\n}", + "description": "Adds a map shape" + }, + "Add Structure shape": { + "prefix": "structure", + "body": "structure ${0:MyStructure} {\n}", + "description": "Adds a structure shape" + }, + "Add @input Structure shape": { + "prefix": "@input", + "body": "@input\nstructure ${1:MyStructure} {$0}", + "description": "Adds a structure shape with the @input trait" + }, + "Add @output Structure shape": { + "prefix": "@output", + "body": "@output\nstructure ${1:MyStructure} {$0}", + "description": "Adds a structure shape with the @output trait" + }, + "Add Union shape": { + "prefix": "union", + "body": "union ${1:myUnion} {\n ${2:myVariantA}: ${3:MyVariantTargetA}\n ${4:myVariantB}: ${0:MyVariantTargetB}\n}", + "description": "Adds a union shape" + } } diff --git a/src/coursier/coursier.ts b/src/coursier/coursier.ts index 1d3eea7..91c6aef 100644 --- a/src/coursier/coursier.ts +++ b/src/coursier/coursier.ts @@ -1,12 +1,12 @@ -import { downloadCoursierIfRequired } from "./download-coursier"; -import { findCoursierOnPath } from "./path-check"; +import { downloadCoursierIfRequired } from './download-coursier'; +import { findCoursierOnPath } from './path-check'; export function getCoursierExecutable(extensionPath: string): Promise { - return findCoursierOnPath(extensionPath).then((paths) => { - if (paths.length > 0) { - return paths[0]; - } else { - return downloadCoursierIfRequired(extensionPath, "v2.0.6"); - } - }); + return findCoursierOnPath(extensionPath).then((paths) => { + if (paths.length > 0) { + return paths[0]; + } else { + return downloadCoursierIfRequired(extensionPath, 'v2.0.6'); + } + }); } diff --git a/src/coursier/download-coursier.ts b/src/coursier/download-coursier.ts index aa65ec7..d88df59 100644 --- a/src/coursier/download-coursier.ts +++ b/src/coursier/download-coursier.ts @@ -1,86 +1,86 @@ -import * as path from "path"; -import { https } from "follow-redirects"; -import { IncomingMessage } from "http"; -import * as fs from "fs"; -import { access, mkdir } from "fs/promises"; +import * as path from 'path'; +import { https } from 'follow-redirects'; +import { IncomingMessage } from 'http'; +import * as fs from 'fs'; +import { access, mkdir } from 'fs/promises'; export function downloadCoursierIfRequired(extensionPath: string, versionPath: string): Promise { - function binPath(filename: string) { - return path.join(extensionPath, filename); - } + function binPath(filename: string) { + return path.join(extensionPath, filename); + } - function createDir() { - return mkdir(extensionPath).catch((err: { code?: string }) => { - return err && err.code === "EEXIST" ? Promise.resolve() : Promise.reject(err); - }); - } + function createDir() { + return mkdir(extensionPath).catch((err: { code?: string }) => { + return err && err.code === 'EEXIST' ? Promise.resolve() : Promise.reject(err); + }); + } - const urls = { - darwin: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-apple-darwin`, - linux: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-pc-linux`, - win32: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-pc-win32.exe`, - }; - const targets = { - darwin: binPath("coursier"), - linux: binPath("coursier"), - win32: binPath("coursier.exe"), - }; + const urls = { + darwin: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-apple-darwin`, + linux: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-pc-linux`, + win32: `https://github.com/coursier/coursier/releases/download/${versionPath}/cs-x86_64-pc-win32.exe`, + }; + const targets = { + darwin: binPath('coursier'), + linux: binPath('coursier'), + win32: binPath('coursier.exe'), + }; - const targetFile = targets[process.platform]; - return validBinFileExists(targetFile).then((valid) => { - return valid ? targetFile : createDir().then(() => downloadFile(urls[process.platform], targetFile)); - }); + const targetFile = targets[process.platform]; + return validBinFileExists(targetFile).then((valid) => { + return valid ? targetFile : createDir().then(() => downloadFile(urls[process.platform], targetFile)); + }); } function validBinFileExists(file: string): Promise { - return access(file, fs.constants.X_OK) - .then(() => true) - .catch(() => false); + return access(file, fs.constants.X_OK) + .then(() => true) + .catch(() => false); } function downloadFile(url: string, targetFile: string): Promise { - function promiseGet(url: string): Promise { - return new Promise((resolve, reject) => { - https.get(url, (response) => { - if (response.statusCode === 200) { - resolve(response); - } else { - reject(new Error(`Server responded with ${response.statusCode}: ${response.statusMessage}`)); - } - }); - }); - } + function promiseGet(url: string): Promise { + return new Promise((resolve, reject) => { + https.get(url, (response) => { + if (response.statusCode === 200) { + resolve(response); + } else { + reject(new Error(`Server responded with ${response.statusCode}: ${response.statusMessage}`)); + } + }); + }); + } - function writeToDisk(response: IncomingMessage): Promise { - return new Promise((resolve, reject) => { - const file = fs.createWriteStream(targetFile, { - flags: "wx", - mode: 0o755, - }); - response.pipe(file); + function writeToDisk(response: IncomingMessage): Promise { + return new Promise((resolve, reject) => { + const file = fs.createWriteStream(targetFile, { + flags: 'wx', + mode: 0o755, + }); + response.pipe(file); - file.on("finish", () => { - console.log(`Finished downloaded file at ${targetFile}`); - resolve(targetFile); - }); + file.on('finish', () => { + console.log(`Finished downloaded file at ${targetFile}`); + resolve(targetFile); + }); - file.on("error", (err: { code: string | undefined }) => { - if (file) { - file.close(); - fs.unlink(targetFile, () => {}); // Delete temp file - } + file.on('error', (err: { code: string | undefined }) => { + if (file) { + file.close(); + fs.unlink(targetFile, () => {}); // Delete temp file + } - if (err.code === "EEXIST") { - console.log(`File already exists at ${targetFile}`); - resolve(targetFile); - } else { - console.error(`File error while downloading file at ${targetFile}`); - console.error(err); - reject(err); - } - }); - }); - } - // adapted from https://stackoverflow.com/a/45007624 - return promiseGet(url).then((resp) => writeToDisk(resp)); + if (err.code === 'EEXIST') { + console.log(`File already exists at ${targetFile}`); + resolve(targetFile); + } else { + console.error(`File error while downloading file at ${targetFile}`); + console.error(err); + reject(err); + } + }); + }); + } + // adapted from https://stackoverflow.com/a/45007624 + return promiseGet(url).then((resp) => writeToDisk(resp)); } diff --git a/src/coursier/path-check.ts b/src/coursier/path-check.ts index d87683d..54a1142 100644 --- a/src/coursier/path-check.ts +++ b/src/coursier/path-check.ts @@ -1,41 +1,41 @@ -import { spawn } from "child_process"; +import { spawn } from 'child_process'; /** * This type is used to bypass the `defaultImpl` when running the tests. */ export type ExecForCode = { - run: (execName: string, args: Array, cwd: string) => Promise; + run: (execName: string, args: Array, cwd: string) => Promise; }; const defaultImpl: ExecForCode = { - run: (execName: string, args: Array, cwd: string) => { - return new Promise((resolve, reject) => { - const options = { cwd }; - const resolveProcess = spawn(execName, args, options); - resolveProcess.on("exit", (exitCode) => { - resolve(exitCode); - }); - resolveProcess.on("error", (err) => { - reject(err); - }); - }); - }, + run: (execName: string, args: Array, cwd: string) => { + return new Promise((resolve, reject) => { + const options = { cwd }; + const resolveProcess = spawn(execName, args, options); + resolveProcess.on('exit', (exitCode) => { + resolve(exitCode); + }); + resolveProcess.on('error', (err) => { + reject(err); + }); + }); + }, }; export function findCoursierOnPath(cwd: string, execForCode: ExecForCode = defaultImpl): Promise> { - function availableOnPath(execName: string): Promise { - return execForCode - .run(execName, ["--help"], cwd) - .then((ec) => ec === 0) - .catch(() => false); - } + function availableOnPath(execName: string): Promise { + return execForCode + .run(execName, ['--help'], cwd) + .then((ec) => ec === 0) + .catch(() => false); + } - const possibleCoursierNames = ["cs", "coursier"]; - return possibleCoursierNames.reduce((accP, current) => { - return accP.then((acc) => { - return availableOnPath(current).then((succeeeded) => { - return succeeeded ? [...acc, current] : acc; - }); - }); - }, Promise.resolve([])); + const possibleCoursierNames = ['cs', 'coursier']; + return possibleCoursierNames.reduce((accP, current) => { + return accP.then((acc) => { + return availableOnPath(current).then((succeeeded) => { + return succeeeded ? [...acc, current] : acc; + }); + }); + }, Promise.resolve([])); } diff --git a/src/extension.ts b/src/extension.ts index 4d847ce..7ee69d0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,21 +1,21 @@ -import * as net from "net"; -import * as fs from "fs"; -import * as child_process from "child_process"; -import * as vscode from "vscode"; -import { SelectorDecorator } from "./selector/selector-decorator"; -import { selectorRunCommandHandler, selectorClearCommandHandler } from "./selector/selector-command-handlers"; +import * as net from 'net'; +import * as fs from 'fs'; +import * as child_process from 'child_process'; +import * as vscode from 'vscode'; +import { SelectorDecorator } from './selector/selector-decorator'; +import { selectorRunCommandHandler, selectorClearCommandHandler } from './selector/selector-command-handlers'; import { - CancellationToken, - DocumentFormattingRequest, - LanguageClient, - LanguageClientOptions, - RequestType, - RevealOutputChannelOn, - StreamInfo, - TextDocumentIdentifier, -} from "vscode-languageclient/node"; -import { getCoursierExecutable } from "./coursier/coursier"; + CancellationToken, + DocumentFormattingRequest, + LanguageClient, + LanguageClientOptions, + RequestType, + RevealOutputChannelOn, + StreamInfo, + TextDocumentIdentifier, +} from 'vscode-languageclient/node'; +import { getCoursierExecutable } from './coursier/coursier'; // Couriser uses an index to determine where to download jvms from: https://get-coursier.io/docs/2.0.6/cli-java#jvm-index // Newer versions of coursier use this index, which is more up to date than the one @@ -23,242 +23,246 @@ import { getCoursierExecutable } from "./coursier/coursier"; // This is a temporary solution to avoid adding logic that determines the version of // coursier on the local machine. In the near future, we will vend the language server // as a standalone executable, and will no longer need couriser to manage the jvm version. -const COURSIER_JVM_INDEX = "https://raw.githubusercontent.com/coursier/jvm-index/master/index.json"; +const COURSIER_JVM_INDEX = 'https://raw.githubusercontent.com/coursier/jvm-index/master/index.json'; let client: LanguageClient; export function activate(context: vscode.ExtensionContext) { - async function createServer(): Promise { - function startServer(executable: string): Promise { - console.log(`Executable located at ${executable}.`); - return new Promise((resolve, reject) => { - const server = net - .createServer((socket) => { - console.log("Creating server"); - - resolve({ - reader: socket, - writer: socket, + async function createServer(): Promise { + function startServer(executable: string): Promise { + console.log(`Executable located at ${executable}.`); + return new Promise((resolve, reject) => { + const server = net + .createServer((socket) => { + console.log('Creating server'); + + resolve({ + reader: socket, + writer: socket, + }); + + socket.on('end', () => console.log('Disconnected')); + }) + .on('error', (err) => { + // handle errors here + reject(err); + }); + + // grab a random port. + server.listen(() => { + // Start the child java process + let options = { cwd: context.extensionPath }; + + let port = (server.address() as net.AddressInfo).port; + + let version = vscode.workspace.getConfiguration('smithyLsp').get('version', '`'); + + // Downloading latest poms + let resolveArgs = [ + 'resolve', + '--mode', + 'force', + 'software.amazon.smithy:smithy-language-server:' + version, + '-r', + 'm2local', + ]; + let resolveProcess = child_process.spawn(executable, resolveArgs, options); + console.log(resolveArgs); + resolveProcess.on('exit', (exitCode) => { + console.log('Exit code : ' + exitCode); + if (exitCode == 0) { + console.log('Launching smithy-language-server version:' + version); + + let launchargs = [ + 'launch', + 'software.amazon.smithy:smithy-language-server:' + version, + // Configure couriser to use java 21 + '--jvm', + // By default, coursier uses AdoptOpenJDK: https://get-coursier.io/docs/2.0.6/cli-java + // We could just say '21' here, and let coursier default to adopt jdk + // 21, but later versions of the jdk are released under the name adoptium. + 'corretto:21', + // The location to download the jvm from is provided by the jvm index. + '--jvm-index', + COURSIER_JVM_INDEX, + '-r', + 'm2local', + '-M', + 'software.amazon.smithy.lsp.Main', + '--', + port.toString(), + ]; + + console.log(launchargs); + + let childProcess = child_process.spawn(executable, launchargs, options); + + childProcess.stdout.on('data', (data) => { + console.log(`stdout: ${data}`); + }); + + childProcess.stderr.on('data', (data) => { + console.error(`stderr: ${data}`); + }); + + childProcess.on('close', (code) => { + console.log(`LSP exited with code ${code}`); + }); + } else { + console.log(`Could not resolve smithy-language-server implementation`); + } + }); + + // Send raw output to a file + if (context.storageUri) { + if (!fs.existsSync(context.storageUri.fsPath)) { + fs.mkdirSync(context.storageUri.fsPath); + } + } + }); }); + } - socket.on("end", () => console.log("Disconnected")); - }) - .on("error", (err) => { - // handle errors here - reject(err); - }); - - // grab a random port. - server.listen(() => { - // Start the child java process - let options = { cwd: context.extensionPath }; - - let port = (server.address() as net.AddressInfo).port; - - let version = vscode.workspace.getConfiguration("smithyLsp").get("version", "`"); - - // Downloading latest poms - let resolveArgs = [ - "resolve", - "--mode", - "force", - "software.amazon.smithy:smithy-language-server:" + version, - "-r", - "m2local", - ]; - let resolveProcess = child_process.spawn(executable, resolveArgs, options); - console.log(resolveArgs); - resolveProcess.on("exit", (exitCode) => { - console.log("Exit code : " + exitCode); - if (exitCode == 0) { - console.log("Launching smithy-language-server version:" + version); - - let launchargs = [ - "launch", - "software.amazon.smithy:smithy-language-server:" + version, - // Configure couriser to use java 21 - "--jvm", - // By default, coursier uses AdoptOpenJDK: https://get-coursier.io/docs/2.0.6/cli-java - // We could just say '21' here, and let coursier default to adopt jdk - // 21, but later versions of the jdk are released under the name adoptium. - "corretto:21", - // The location to download the jvm from is provided by the jvm index. - "--jvm-index", - COURSIER_JVM_INDEX, - "-r", - "m2local", - "-M", - "software.amazon.smithy.lsp.Main", - "--", - port.toString(), - ]; - - console.log(launchargs); - - let childProcess = child_process.spawn(executable, launchargs, options); - - childProcess.stdout.on("data", (data) => { - console.log(`stdout: ${data}`); - }); - - childProcess.stderr.on("data", (data) => { - console.error(`stderr: ${data}`); - }); - - childProcess.on("close", (code) => { - console.log(`LSP exited with code ${code}`); - }); - } else { - console.log(`Could not resolve smithy-language-server implementation`); - } - }); - - // Send raw output to a file - if (context.storageUri) { - if (!fs.existsSync(context.storageUri.fsPath)) { - fs.mkdirSync(context.storageUri.fsPath); - } - } - }); - }); + const binaryPath = await getCoursierExecutable(context.globalStoragePath); + return await startServer(binaryPath); } - const binaryPath = await getCoursierExecutable(context.globalStoragePath); - return await startServer(binaryPath); - } + // Create the language client and start the client. + client = new LanguageClient('smithyLsp', 'Smithy LSP', createServer, getClientOptions()); - // Create the language client and start the client. - client = new LanguageClient("smithyLsp", "Smithy LSP", createServer, getClientOptions()); + // Set client on `this` context to use with command handlers. + this.client = client; - // Set client on `this` context to use with command handlers. - this.client = client; + const smithyContentProvider = createSmithyContentProvider(client); + context.subscriptions.push( + vscode.workspace.registerTextDocumentContentProvider('smithyjar', smithyContentProvider) + ); - const smithyContentProvider = createSmithyContentProvider(client); - context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider("smithyjar", smithyContentProvider)); + const smithyFormattingEditProvider = createSmithyFormattingEditProvider(client); + context.subscriptions.push( + vscode.languages.registerDocumentFormattingEditProvider('smithy', smithyFormattingEditProvider) + ); - const smithyFormattingEditProvider = createSmithyFormattingEditProvider(client); - context.subscriptions.push( - vscode.languages.registerDocumentFormattingEditProvider("smithy", smithyFormattingEditProvider) - ); + // Set default expression input, and use context to hold state between command invocations. + this.expression = 'Enter Selector Expression'; + this.selectorDecorator = new SelectorDecorator(); - // Set default expression input, and use context to hold state between command invocations. - this.expression = "Enter Selector Expression"; - this.selectorDecorator = new SelectorDecorator(); + // Register selector commands. + context.subscriptions.push(vscode.commands.registerCommand('smithy.runSelector', selectorRunCommandHandler, this)); + context.subscriptions.push( + vscode.commands.registerCommand('smithy.clearSelector', selectorClearCommandHandler, this) + ); - // Register selector commands. - context.subscriptions.push(vscode.commands.registerCommand("smithy.runSelector", selectorRunCommandHandler, this)); - context.subscriptions.push( - vscode.commands.registerCommand("smithy.clearSelector", selectorClearCommandHandler, this) - ); - - // Start the client. This will also launch the server - client.start(); + // Start the client. This will also launch the server + client.start(); } function getClientOptions(): LanguageClientOptions { - let workspaceFolder: vscode.WorkspaceFolder; - - let rootPath: string = vscode.workspace.getConfiguration("smithyLsp").get("rootPath"); + let workspaceFolder: vscode.WorkspaceFolder; + + let rootPath: string = vscode.workspace.getConfiguration('smithyLsp').get('rootPath'); + + if (rootPath) { + const workspaceRoot = getWorkspaceRoot(); + if (rootPath.startsWith('${workspaceRoot}') && workspaceRoot === '') { + console.warn(`Unable to retrieve the workspace root.`); + } + workspaceFolder = { + uri: vscode.Uri.file(rootPath.replace('${workspaceRoot}', workspaceRoot)), + name: 'smithy-lsp-root-path', + index: 1, + }; + } - if (rootPath) { - const workspaceRoot = getWorkspaceRoot(); - if (rootPath.startsWith("${workspaceRoot}") && workspaceRoot === "") { - console.warn(`Unable to retrieve the workspace root.`); + // Configure file patterns relative to the workspace folder. + let filePattern: vscode.GlobPattern = '**/{smithy-build}.json'; + let selectorPattern: string = null; + if (workspaceFolder) { + filePattern = new vscode.RelativePattern(workspaceFolder, filePattern); + selectorPattern = `${workspaceFolder.uri.fsPath}/**/*`; } - workspaceFolder = { - uri: vscode.Uri.file(rootPath.replace("${workspaceRoot}", workspaceRoot)), - name: "smithy-lsp-root-path", - index: 1, + + // Options to control the language client + return { + // Register the server for plain text documents + documentSelector: [ + { scheme: 'file', language: 'smithy', pattern: selectorPattern }, + { scheme: 'smithyjar', language: 'smithy', pattern: selectorPattern }, + { scheme: 'file', language: 'json', pattern: '**/{smithy-build,.smithy-project}.json' }, + ], + synchronize: { + // Notify the server about file changes to 'smithy-build.json' files contained in the workspace + fileEvents: vscode.workspace.createFileSystemWatcher(filePattern), + }, + outputChannelName: 'Smithy Language Server', + + workspaceFolder, + + initializationOptions: { + 'diagnostics.minimumSeverity': vscode.workspace + .getConfiguration('smithyLsp') + .get('diagnostics.minimumSeverity'), + onlyReloadOnSave: vscode.workspace.getConfiguration('smithyLsp').get('onlyReloadOnSave'), + }, + + // Don't switch to output window when the server returns output. + revealOutputChannelOn: RevealOutputChannelOn.Never, + progressOnInitialization: true, }; - } - - // Configure file patterns relative to the workspace folder. - let filePattern: vscode.GlobPattern = "**/{smithy-build}.json"; - let selectorPattern: string = null; - if (workspaceFolder) { - filePattern = new vscode.RelativePattern(workspaceFolder, filePattern); - selectorPattern = `${workspaceFolder.uri.fsPath}/**/*`; - } - - // Options to control the language client - return { - // Register the server for plain text documents - documentSelector: [ - { scheme: "file", language: "smithy", pattern: selectorPattern }, - { scheme: "smithyjar", language: "smithy", pattern: selectorPattern }, - { scheme: "file", language: "json", pattern: "**/{smithy-build,.smithy-project}.json" }, - ], - synchronize: { - // Notify the server about file changes to 'smithy-build.json' files contained in the workspace - fileEvents: vscode.workspace.createFileSystemWatcher(filePattern), - }, - outputChannelName: "Smithy Language Server", - - workspaceFolder, - - initializationOptions: { - "diagnostics.minimumSeverity": vscode.workspace.getConfiguration("smithyLsp").get("diagnostics.minimumSeverity"), - onlyReloadOnSave: vscode.workspace.getConfiguration("smithyLsp").get("onlyReloadOnSave"), - }, - - // Don't switch to output window when the server returns output. - revealOutputChannelOn: RevealOutputChannelOn.Never, - progressOnInitialization: true, - }; } export function deactivate(): Thenable | undefined { - if (!client) { - return undefined; - } - return client.stop(); + if (!client) { + return undefined; + } + return client.stop(); } function getWorkspaceRoot(): string | undefined { - let folders = vscode.workspace.workspaceFolders; - if (!folders || folders.length === 0) { - return ""; - } - let folder = folders[0]; - if (folder.uri.scheme === "file") { - return folder.uri.fsPath; - } - return ""; + let folders = vscode.workspace.workspaceFolders; + if (!folders || folders.length === 0) { + return ''; + } + let folder = folders[0]; + if (folder.uri.scheme === 'file') { + return folder.uri.fsPath; + } + return ''; } function createSmithyContentProvider(languageClient: LanguageClient): vscode.TextDocumentContentProvider { - return { - provideTextDocumentContent: async (uri: vscode.Uri, token: CancellationToken): Promise => { - return languageClient - .sendRequest(ClassFileContentsRequest.type, { uri: uri.toString() }, token) - .then((v: string): string => { - return v || ""; - }); - }, - }; + return { + provideTextDocumentContent: async (uri: vscode.Uri, token: CancellationToken): Promise => { + return languageClient + .sendRequest(ClassFileContentsRequest.type, { uri: uri.toString() }, token) + .then((v: string): string => { + return v || ''; + }); + }, + }; } function createSmithyFormattingEditProvider(languageClient: LanguageClient): vscode.DocumentFormattingEditProvider { - return { - provideDocumentFormattingEdits: async ( - document: vscode.TextDocument, - options: vscode.FormattingOptions, - token: CancellationToken - ): Promise => { - document.uri; - return languageClient - .sendRequest( - DocumentFormattingRequest.type, - { textDocument: { uri: document.uri.toString() }, options: options }, - token - ) - .then((v: vscode.TextEdit[]): vscode.TextEdit[] => { - return v; - }); - }, - }; + return { + provideDocumentFormattingEdits: async ( + document: vscode.TextDocument, + options: vscode.FormattingOptions, + token: CancellationToken + ): Promise => { + document.uri; + return languageClient + .sendRequest( + DocumentFormattingRequest.type, + { textDocument: { uri: document.uri.toString() }, options: options }, + token + ) + .then((v: vscode.TextEdit[]): vscode.TextEdit[] => { + return v; + }); + }, + }; } export namespace ClassFileContentsRequest { - export const type = new RequestType("smithy/jarFileContents"); + export const type = new RequestType('smithy/jarFileContents'); } diff --git a/src/selector/selector-command-handlers.ts b/src/selector/selector-command-handlers.ts index 5f5c9a4..c158692 100644 --- a/src/selector/selector-command-handlers.ts +++ b/src/selector/selector-command-handlers.ts @@ -1,31 +1,37 @@ -import { Position, Range, window } from "vscode"; -import { SelectorCommandRequest } from "./selector-command-request"; +import { Position, Range, window } from 'vscode'; +import { SelectorCommandRequest } from './selector-command-request'; export async function selectorClearCommandHandler() { - this.selectorDecorator.clear(); + this.selectorDecorator.clear(); } export async function selectorRunCommandHandler() { - const expression = await window.showInputBox({ - title: "Run a selector", - value: this.expression, - }); - const decorator = this.selectorDecorator; - let response = []; - // Don't do anything if expression was not populated. - if (expression) { - decorator.clear(); - this.expression = expression; - response = await this.client.sendRequest(SelectorCommandRequest.type, { expression: expression }); - const activeEditor = window.activeTextEditor; - const ranges = []; - for (const location of response) { - if (location["uri"].endsWith(activeEditor.document.fileName)) { - const startPosition = new Position(location["range"]["start"]["line"], location["range"]["start"]["character"]); - const endPosition = new Position(location["range"]["end"]["line"], location["range"]["end"]["character"]); - ranges.push(new Range(startPosition, endPosition)); - } + const expression = await window.showInputBox({ + title: 'Run a selector', + value: this.expression, + }); + const decorator = this.selectorDecorator; + let response = []; + // Don't do anything if expression was not populated. + if (expression) { + decorator.clear(); + this.expression = expression; + response = await this.client.sendRequest(SelectorCommandRequest.type, { expression: expression }); + const activeEditor = window.activeTextEditor; + const ranges = []; + for (const location of response) { + if (location['uri'].endsWith(activeEditor.document.fileName)) { + const startPosition = new Position( + location['range']['start']['line'], + location['range']['start']['character'] + ); + const endPosition = new Position( + location['range']['end']['line'], + location['range']['end']['character'] + ); + ranges.push(new Range(startPosition, endPosition)); + } + } + decorator.set(activeEditor, ranges); } - decorator.set(activeEditor, ranges); - } } diff --git a/src/selector/selector-command-request.ts b/src/selector/selector-command-request.ts index 757d2c5..6f910f2 100644 --- a/src/selector/selector-command-request.ts +++ b/src/selector/selector-command-request.ts @@ -1,9 +1,9 @@ -import { RequestType } from "vscode-languageclient"; +import { RequestType } from 'vscode-languageclient'; interface SelectorParams { - expression: String; + expression: String; } export namespace SelectorCommandRequest { - export const type = new RequestType("smithy/selectorCommand"); + export const type = new RequestType('smithy/selectorCommand'); } diff --git a/src/selector/selector-decorator.ts b/src/selector/selector-decorator.ts index 449195f..80163cd 100644 --- a/src/selector/selector-decorator.ts +++ b/src/selector/selector-decorator.ts @@ -1,35 +1,35 @@ -import { Range, TextEditor, TextEditorDecorationType, window, workspace } from "vscode"; +import { Range, TextEditor, TextEditorDecorationType, window, workspace } from 'vscode'; export interface ISelectorDecorator { - getDecorationType(): TextEditorDecorationType; - clear(): void; - set(textEditor: TextEditor, ranges: readonly Range[]): void; + getDecorationType(): TextEditorDecorationType; + clear(): void; + set(textEditor: TextEditor, ranges: readonly Range[]): void; } export class SelectorDecorator { - private decorationType: TextEditorDecorationType; + private decorationType: TextEditorDecorationType; - constructor() { - this.decorationType = this.createDecorationType(); - } + constructor() { + this.decorationType = this.createDecorationType(); + } - getDecorationType(): TextEditorDecorationType { - return this.decorationType; - } + getDecorationType(): TextEditorDecorationType { + return this.decorationType; + } - clear(): void { - this.decorationType.dispose(); - this.decorationType = this.createDecorationType(); - } + clear(): void { + this.decorationType.dispose(); + this.decorationType = this.createDecorationType(); + } - createDecorationType(): TextEditorDecorationType { - return window.createTextEditorDecorationType({ - border: "dotted", - borderColor: "#C44536", - }); - } + createDecorationType(): TextEditorDecorationType { + return window.createTextEditorDecorationType({ + border: 'dotted', + borderColor: '#C44536', + }); + } - set(textEditor: TextEditor, ranges: readonly Range[]): void { - textEditor.setDecorations(this.decorationType, ranges); - } + set(textEditor: TextEditor, ranges: readonly Range[]): void { + textEditor.setDecorations(this.decorationType, ranges); + } } diff --git a/syntaxes/smithy.tmLanguage.json b/syntaxes/smithy.tmLanguage.json index 6fddcde..82db6eb 100644 --- a/syntaxes/smithy.tmLanguage.json +++ b/syntaxes/smithy.tmLanguage.json @@ -1,563 +1,563 @@ { - "name": "Smithy", - "fileTypes": ["smithy"], - "scopeName": "source.smithy", - "uuid": "9c3e617f-4d4a-4370-9194-2e82173c1610", - "foldingStartMarker": "(\\{|\\[)\\s*", - "foldingStopMarker": "\\s*(\\}|\\])", - "patterns": [ - { - "include": "#comment" - }, - { - "name": "meta.keyword.statement.control.smithy", - "begin": "^(\\$)([A-Z-a-z_][A-Z-a-z0-9_]*)(:)\\s*", - "end": "\\n", - "beginCaptures": { - "1": { - "name": "keyword.statement.control.smithy" - }, - "2": { - "name": "support.type.property-name.smithy" - }, - "3": { - "name": "punctuation.separator.dictionary.pair.smithy" - } - }, - "patterns": [ - { - "include": "#value" - }, - { - "match": "[^\\n]", - "name": "invalid.illegal.control.smithy" - } - ] - }, - { - "name": "meta.keyword.statement.metadata.smithy", - "begin": "^(metadata)\\s+(.+)\\s*(=)\\s*", - "beginCaptures": { - "1": { - "name": "keyword.statement.smithy" - }, - "2": { - "name": "variable.other.smithy" - }, - "3": { - "name": "keyword.operator.smithy" - } - }, - "end": "\\n", - "patterns": [ - { - "include": "#value" - } - ] - }, - { - "name": "meta.keyword.statement.namespace.smithy", - "begin": "^(namespace)\\s+", - "beginCaptures": { - "1": { - "name": "keyword.statement.smithy" - } - }, - "end": "\\n", - "patterns": [ - { - "match": "[A-Z-a-z_][A-Z-a-z0-9_]*(\\.[A-Z-a-z_][A-Z-a-z0-9_]*)*", - "name": "entity.name.type.smithy" - }, - { - "match": "[^\\n]", - "name": "invalid.illegal.namespace.smithy" - } - ] - }, - { - "name": "meta.keyword.statement.use.smithy", - "begin": "^(use)\\s+", - "beginCaptures": { - "1": { - "name": "keyword.statement.smithy" - } - }, - "end": "\\n", - "patterns": [ - { - "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_]*)*", - "name": "entity.name.type.smithy" - }, - { - "match": "[^\\n]", - "name": "invalid.illegal.use.smithy" - } - ] - }, - { - "include": "#trait" - }, - { - "name": "meta.keyword.statement.shape.smithy", - "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+(\\[)", - "beginCaptures": { - "1": { - "name": "keyword.statement.smithy" - }, - "2": { - "name": "entity.name.type.smithy" - }, - "3": { - "name": "keyword.statement.with.smithy" - }, - "4": { - "name": "punctuation.definition.array.begin.smithy" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "punctuation.definition.array.end.smithy" - } - }, - "patterns": [ - { - "include": "#identifier", - "name": "entity.name.type.smithy" - }, - { - "include": "#comment" - }, - { - "match": ",", - "name": "punctuation.separator.array.smithy" - } - ] - }, - { - "name": "meta.keyword.statement.shape.smithy", - "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_]*)", - "captures": { - "1": { - "name": "keyword.statement.smithy" - }, - "2": { - "name": "entity.name.type.smithy" - } - } - }, - { - "name": "meta.keyword.statement.shape.smithy", - "begin": "^(structure)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)(?:\\s+(for)\\s+([0-9a-zA-Z\\.#-]+))?\\s+(with)\\s+(\\[)", - "beginCaptures": { - "1": { - "name": "keyword.statement.smithy" - }, - "2": { - "name": "entity.name.type.smithy" - }, - "3": { - "name": "keyword.statement.for-resource.smithy" - }, - "4": { - "name": "entity.name.type.smithy" - }, - "5": { - "name": "keyword.statement.with.smithy" - }, - "6": { - "name": "punctuation.definition.array.begin.smithy" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "punctuation.definition.array.end.smithy" - } - }, - "patterns": [ - { - "include": "#identifier", - "name": "entity.name.type.smithy" - }, - { - "include": "#comment" - }, - { - "match": ",", - "name": "punctuation.separator.array.smithy" - } - ] - }, - { - "name": "meta.keyword.statement.shape.smithy", - "match": "^(structure)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)(?:\\s+(for)\\s+([0-9a-zA-Z\\.#-]+))?", - "captures": { - "1": { - "name": "keyword.statement.smithy" - }, - "2": { - "name": "entity.name.type.smithy" - }, - "3": { - "name": "keyword.statement.for-resource.smithy" - }, - "4": { - "name": "entity.name.type.smithy" - } - } - }, - { - "begin": "\\{", - "beginCaptures": { - "0": { - "name": "punctuation.definition.dictionary.begin.smithy" - } - }, - "end": "\\}", - "endCaptures": { - "0": { - "name": "punctuation.definition.dictionary.end.smithy" - } - }, - "patterns": [ - { - "include": "#shape_inner" - } - ] - }, - { - "name": "meta.keyword.statement.apply.smithy", - "begin": "^(apply)\\s+", - "end": "\\n", - "beginCaptures": { - "1": { - "name": "keyword.statement.smithy" - } - }, - "patterns": [ - { - "include": "#trait" - }, - { - "include": "#shapeid" - }, - { - "match": "[^\\n]", - "name": "invalid.illegal.apply.smithy" - } - ] - } - ], - "repository": { - "with_statement": { - "begin": "(with)\\s+(\\[)", - "beginCaptures": { - "1": { - "name": "keyword.statement.with.smithy" - }, - "2": { - "name": "punctuation.definition.array.begin.smithy" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "punctuation.definition.array.end.smithy" - } - }, - "patterns": [ - { - "match": ",", - "name": "punctuation.separator.array.smithy" - }, - { - "include": "#identifier" - }, - { - "include": "#comment" - } - ] - }, - "comment": { - "patterns": [ - { - "include": "#doc_comment" - }, - { - "include": "#line_comment" - } - ] - }, - "doc_comment": { - "match": "(///.*)", - "name": "comment.block.documentation.smithy" - }, - "line_comment": { - "match": "(//.*)", - "name": "comment.line.double-slash.smithy" - }, - "trait": { - "patterns": [ - { - "name": "meta.keyword.statement.trait.smithy", - "begin": "(@)([0-9a-zA-Z\\.#-]+)(\\()", - "beginCaptures": { - "1": { - "name": "punctuation.definition.annotation.smithy" + "name": "Smithy", + "fileTypes": ["smithy"], + "scopeName": "source.smithy", + "uuid": "9c3e617f-4d4a-4370-9194-2e82173c1610", + "foldingStartMarker": "(\\{|\\[)\\s*", + "foldingStopMarker": "\\s*(\\}|\\])", + "patterns": [ + { + "include": "#comment" + }, + { + "name": "meta.keyword.statement.control.smithy", + "begin": "^(\\$)([A-Z-a-z_][A-Z-a-z0-9_]*)(:)\\s*", + "end": "\\n", + "beginCaptures": { + "1": { + "name": "keyword.statement.control.smithy" + }, + "2": { + "name": "support.type.property-name.smithy" + }, + "3": { + "name": "punctuation.separator.dictionary.pair.smithy" + } }, - "2": { - "name": "storage.type.annotation.smithy" + "patterns": [ + { + "include": "#value" + }, + { + "match": "[^\\n]", + "name": "invalid.illegal.control.smithy" + } + ] + }, + { + "name": "meta.keyword.statement.metadata.smithy", + "begin": "^(metadata)\\s+(.+)\\s*(=)\\s*", + "beginCaptures": { + "1": { + "name": "keyword.statement.smithy" + }, + "2": { + "name": "variable.other.smithy" + }, + "3": { + "name": "keyword.operator.smithy" + } }, - "3": { - "name": "punctuation.definition.dictionary.begin.smithy" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.dictionary.end.smithy" - } - }, - "patterns": [ - { - "include": "#object_inner" + "end": "\\n", + "patterns": [ + { + "include": "#value" + } + ] + }, + { + "name": "meta.keyword.statement.namespace.smithy", + "begin": "^(namespace)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.statement.smithy" + } + }, + "end": "\\n", + "patterns": [ + { + "match": "[A-Z-a-z_][A-Z-a-z0-9_]*(\\.[A-Z-a-z_][A-Z-a-z0-9_]*)*", + "name": "entity.name.type.smithy" + }, + { + "match": "[^\\n]", + "name": "invalid.illegal.namespace.smithy" + } + ] + }, + { + "name": "meta.keyword.statement.use.smithy", + "begin": "^(use)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.statement.smithy" + } }, - { - "include": "#value" + "end": "\\n", + "patterns": [ + { + "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_]*)*", + "name": "entity.name.type.smithy" + }, + { + "match": "[^\\n]", + "name": "invalid.illegal.use.smithy" + } + ] + }, + { + "include": "#trait" + }, + { + "name": "meta.keyword.statement.shape.smithy", + "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+(\\[)", + "beginCaptures": { + "1": { + "name": "keyword.statement.smithy" + }, + "2": { + "name": "entity.name.type.smithy" + }, + "3": { + "name": "keyword.statement.with.smithy" + }, + "4": { + "name": "punctuation.definition.array.begin.smithy" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.smithy" + } + }, + "patterns": [ + { + "include": "#identifier", + "name": "entity.name.type.smithy" + }, + { + "include": "#comment" + }, + { + "match": ",", + "name": "punctuation.separator.array.smithy" + } + ] + }, + { + "name": "meta.keyword.statement.shape.smithy", + "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_]*)", + "captures": { + "1": { + "name": "keyword.statement.smithy" + }, + "2": { + "name": "entity.name.type.smithy" + } } - ] }, { - "name": "meta.keyword.statement.trait.smithy", - "match": "(@)([0-9a-zA-Z\\.#-]+)", - "captures": { - "1": { - "name": "punctuation.definition.annotation.smithy" + "name": "meta.keyword.statement.shape.smithy", + "begin": "^(structure)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)(?:\\s+(for)\\s+([0-9a-zA-Z\\.#-]+))?\\s+(with)\\s+(\\[)", + "beginCaptures": { + "1": { + "name": "keyword.statement.smithy" + }, + "2": { + "name": "entity.name.type.smithy" + }, + "3": { + "name": "keyword.statement.for-resource.smithy" + }, + "4": { + "name": "entity.name.type.smithy" + }, + "5": { + "name": "keyword.statement.with.smithy" + }, + "6": { + "name": "punctuation.definition.array.begin.smithy" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.smithy" + } }, - "2": { - "name": "storage.type.annotation.smithy" + "patterns": [ + { + "include": "#identifier", + "name": "entity.name.type.smithy" + }, + { + "include": "#comment" + }, + { + "match": ",", + "name": "punctuation.separator.array.smithy" + } + ] + }, + { + "name": "meta.keyword.statement.shape.smithy", + "match": "^(structure)\\s+([A-Z-a-z_][A-Z-a-z0-9_]*)(?:\\s+(for)\\s+([0-9a-zA-Z\\.#-]+))?", + "captures": { + "1": { + "name": "keyword.statement.smithy" + }, + "2": { + "name": "entity.name.type.smithy" + }, + "3": { + "name": "keyword.statement.for-resource.smithy" + }, + "4": { + "name": "entity.name.type.smithy" + } } - } - } - ] - }, - "value": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#keywords" - }, - { - "include": "#number" - }, - { - "include": "#string" - }, - { - "include": "#array" - }, - { - "include": "#object" - } - ] - }, - "array": { - "begin": "\\[", - "beginCaptures": { - "0": { - "name": "punctuation.definition.array.begin.smithy" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "punctuation.definition.array.end.smithy" - } - }, - "name": "meta.structure.array.smithy", - "patterns": [ - { - "include": "#value" - }, - { - "match": ",", - "name": "punctuation.separator.array.smithy" - }, - { - "match": "[^\\s\\]]", - "name": "invalid.illegal.array.smithy" - } - ] - }, - "keywords": { - "match": "\\b(?:true|false|null)\\b", - "name": "constant.language.smithy" - }, - "number": { - "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 )", - "name": "constant.numeric.smithy" - }, - "object": { - "begin": "\\{", - "beginCaptures": { - "0": { - "name": "punctuation.definition.dictionary.begin.smithy" - } - }, - "end": "\\}", - "endCaptures": { - "0": { - "name": "punctuation.definition.dictionary.end.smithy" - } - }, - "name": "meta.structure.dictionary.smithy", - "patterns": [ - { - "include": "#object_inner" - } - ] - }, - "object_inner": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string_key" - }, - { - "match": ":", - "name": "punctuation.separator.dictionary.key-value.smithy" - }, - { - "match": "=", - "name": "keyword.operator.smithy" - }, - { - "name": "meta.structure.dictionary.value.smithy", - "include": "#value" - }, - { - "match": ",", - "name": "punctuation.separator.dictionary.pair.smithy" - } - ] - }, - "shape_inner": { - "patterns": [ - { - "include": "#trait" }, { - "match": ":=", - "name": "punctuation.separator.dictionary.inline-struct.smithy" - }, - { - "include": "#with_statement" - }, - { - "include": "#elided_target" - }, - { - "include": "#object_inner" - } - ] - }, - "string_key": { - "patterns": [ - { - "include": "#identifier_key" - }, - { - "include": "#dquote_key" - } - ] - }, - "identifier_key": { - "name": "support.type.property-name.smithy", - "match": "[A-Z-a-z0-9_\\.#$]+(?=\\s*:)" - }, - "dquote_key": { - "name": "support.type.property-name.smithy", - "match": "\".*\"(?=\\s*:)" - }, - "string": { - "patterns": [ - { - "include": "#textblock" - }, - { - "include": "#dquote" - }, - { - "include": "#shapeid" - } - ] - }, - "textblock": { - "name": "string.quoted.double.smithy", - "begin": "\"\"\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.smithy" - } - }, - "end": "\"\"\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.smithy" - } - }, - "patterns": [ - { - "match": "\\\\.", - "name": "constant.character.escape.smithy" - } - ] - }, - "dquote": { - "name": "string.quoted.double.smithy", - "begin": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.smithy" - } - }, - "end": "\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.smithy" - } - }, - "patterns": [ - { - "match": "\\\\.", - "name": "constant.character.escape.smithy" - } - ] - }, - "identifier": { - "name": "entity.name.type.smithy", - "match": "[A-Z-a-z_][A-Z-a-z0-9_]*" - }, - "shapeid": { - "name": "entity.name.type.smithy", - "match": "[A-Z-a-z_][A-Z-a-z0-9_\\.#$]*" - }, - "elided_target": { - "match": "(\\$)([A-Z-a-z0-9_\\.#$]+)", - "captures": { - "1": { - "name": "keyword.statement.elision.smithy" - }, - "2": { - "name": "support.type.property-name.smithy" + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.dictionary.begin.smithy" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.dictionary.end.smithy" + } + }, + "patterns": [ + { + "include": "#shape_inner" + } + ] + }, + { + "name": "meta.keyword.statement.apply.smithy", + "begin": "^(apply)\\s+", + "end": "\\n", + "beginCaptures": { + "1": { + "name": "keyword.statement.smithy" + } + }, + "patterns": [ + { + "include": "#trait" + }, + { + "include": "#shapeid" + }, + { + "match": "[^\\n]", + "name": "invalid.illegal.apply.smithy" + } + ] + } + ], + "repository": { + "with_statement": { + "begin": "(with)\\s+(\\[)", + "beginCaptures": { + "1": { + "name": "keyword.statement.with.smithy" + }, + "2": { + "name": "punctuation.definition.array.begin.smithy" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.smithy" + } + }, + "patterns": [ + { + "match": ",", + "name": "punctuation.separator.array.smithy" + }, + { + "include": "#identifier" + }, + { + "include": "#comment" + } + ] + }, + "comment": { + "patterns": [ + { + "include": "#doc_comment" + }, + { + "include": "#line_comment" + } + ] + }, + "doc_comment": { + "match": "(///.*)", + "name": "comment.block.documentation.smithy" + }, + "line_comment": { + "match": "(//.*)", + "name": "comment.line.double-slash.smithy" + }, + "trait": { + "patterns": [ + { + "name": "meta.keyword.statement.trait.smithy", + "begin": "(@)([0-9a-zA-Z\\.#-]+)(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.annotation.smithy" + }, + "2": { + "name": "storage.type.annotation.smithy" + }, + "3": { + "name": "punctuation.definition.dictionary.begin.smithy" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.dictionary.end.smithy" + } + }, + "patterns": [ + { + "include": "#object_inner" + }, + { + "include": "#value" + } + ] + }, + { + "name": "meta.keyword.statement.trait.smithy", + "match": "(@)([0-9a-zA-Z\\.#-]+)", + "captures": { + "1": { + "name": "punctuation.definition.annotation.smithy" + }, + "2": { + "name": "storage.type.annotation.smithy" + } + } + } + ] + }, + "value": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#keywords" + }, + { + "include": "#number" + }, + { + "include": "#string" + }, + { + "include": "#array" + }, + { + "include": "#object" + } + ] + }, + "array": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.array.begin.smithy" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.smithy" + } + }, + "name": "meta.structure.array.smithy", + "patterns": [ + { + "include": "#value" + }, + { + "match": ",", + "name": "punctuation.separator.array.smithy" + }, + { + "match": "[^\\s\\]]", + "name": "invalid.illegal.array.smithy" + } + ] + }, + "keywords": { + "match": "\\b(?:true|false|null)\\b", + "name": "constant.language.smithy" + }, + "number": { + "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 )", + "name": "constant.numeric.smithy" + }, + "object": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.dictionary.begin.smithy" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.dictionary.end.smithy" + } + }, + "name": "meta.structure.dictionary.smithy", + "patterns": [ + { + "include": "#object_inner" + } + ] + }, + "object_inner": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string_key" + }, + { + "match": ":", + "name": "punctuation.separator.dictionary.key-value.smithy" + }, + { + "match": "=", + "name": "keyword.operator.smithy" + }, + { + "name": "meta.structure.dictionary.value.smithy", + "include": "#value" + }, + { + "match": ",", + "name": "punctuation.separator.dictionary.pair.smithy" + } + ] + }, + "shape_inner": { + "patterns": [ + { + "include": "#trait" + }, + { + "match": ":=", + "name": "punctuation.separator.dictionary.inline-struct.smithy" + }, + { + "include": "#with_statement" + }, + { + "include": "#elided_target" + }, + { + "include": "#object_inner" + } + ] + }, + "string_key": { + "patterns": [ + { + "include": "#identifier_key" + }, + { + "include": "#dquote_key" + } + ] + }, + "identifier_key": { + "name": "support.type.property-name.smithy", + "match": "[A-Z-a-z0-9_\\.#$]+(?=\\s*:)" + }, + "dquote_key": { + "name": "support.type.property-name.smithy", + "match": "\".*\"(?=\\s*:)" + }, + "string": { + "patterns": [ + { + "include": "#textblock" + }, + { + "include": "#dquote" + }, + { + "include": "#shapeid" + } + ] + }, + "textblock": { + "name": "string.quoted.double.smithy", + "begin": "\"\"\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.smithy" + } + }, + "end": "\"\"\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.smithy" + } + }, + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.smithy" + } + ] + }, + "dquote": { + "name": "string.quoted.double.smithy", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.smithy" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.smithy" + } + }, + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.smithy" + } + ] + }, + "identifier": { + "name": "entity.name.type.smithy", + "match": "[A-Z-a-z_][A-Z-a-z0-9_]*" + }, + "shapeid": { + "name": "entity.name.type.smithy", + "match": "[A-Z-a-z_][A-Z-a-z0-9_\\.#$]*" + }, + "elided_target": { + "match": "(\\$)([A-Z-a-z0-9_\\.#$]+)", + "captures": { + "1": { + "name": "keyword.statement.elision.smithy" + }, + "2": { + "name": "support.type.property-name.smithy" + } + } } - } } - } } diff --git a/test-fixtures/suite1/smithy-build.json b/test-fixtures/suite1/smithy-build.json index 4cedfa3..9674e26 100644 --- a/test-fixtures/suite1/smithy-build.json +++ b/test-fixtures/suite1/smithy-build.json @@ -1,8 +1,8 @@ { - "version": "1.0", - "sources": ["./main.smithy"], - "maven": { - "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], - "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] - } + "version": "1.0", + "sources": ["./main.smithy"], + "maven": { + "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], + "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] + } } diff --git a/test-fixtures/suite2/smithy-build.json b/test-fixtures/suite2/smithy-build.json index 4cedfa3..9674e26 100644 --- a/test-fixtures/suite2/smithy-build.json +++ b/test-fixtures/suite2/smithy-build.json @@ -1,8 +1,8 @@ { - "version": "1.0", - "sources": ["./main.smithy"], - "maven": { - "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], - "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] - } + "version": "1.0", + "sources": ["./main.smithy"], + "maven": { + "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], + "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] + } } diff --git a/test-fixtures/suite3/smithy-build.json b/test-fixtures/suite3/smithy-build.json index 4cedfa3..9674e26 100644 --- a/test-fixtures/suite3/smithy-build.json +++ b/test-fixtures/suite3/smithy-build.json @@ -1,8 +1,8 @@ { - "version": "1.0", - "sources": ["./main.smithy"], - "maven": { - "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], - "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] - } + "version": "1.0", + "sources": ["./main.smithy"], + "maven": { + "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0"], + "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] + } } diff --git a/test-fixtures/suite4/smithy/smithy-build.json b/test-fixtures/suite4/smithy/smithy-build.json index bd67f41..28dfd2c 100644 --- a/test-fixtures/suite4/smithy/smithy-build.json +++ b/test-fixtures/suite4/smithy/smithy-build.json @@ -1,8 +1,11 @@ { - "version": "1.0", - "sources": ["./main.smithy"], - "maven": { - "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0", "software.amazon.smithy:smithy-waiters:1.40.0"], - "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] - } + "version": "1.0", + "sources": ["./main.smithy"], + "maven": { + "dependencies": [ + "software.amazon.smithy:smithy-aws-traits:1.40.0", + "software.amazon.smithy:smithy-waiters:1.40.0" + ], + "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] + } } diff --git a/test-fixtures/suite5/smithy/smithy-build.json b/test-fixtures/suite5/smithy/smithy-build.json index bd67f41..28dfd2c 100644 --- a/test-fixtures/suite5/smithy/smithy-build.json +++ b/test-fixtures/suite5/smithy/smithy-build.json @@ -1,8 +1,11 @@ { - "version": "1.0", - "sources": ["./main.smithy"], - "maven": { - "dependencies": ["software.amazon.smithy:smithy-aws-traits:1.40.0", "software.amazon.smithy:smithy-waiters:1.40.0"], - "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] - } + "version": "1.0", + "sources": ["./main.smithy"], + "maven": { + "dependencies": [ + "software.amazon.smithy:smithy-aws-traits:1.40.0", + "software.amazon.smithy:smithy-waiters:1.40.0" + ], + "repositories": [{ "url": "https://repo1.maven.org/maven2/" }] + } } diff --git a/test-fixtures/suite6/smithy-build.json b/test-fixtures/suite6/smithy-build.json index 703ffb7..0445027 100644 --- a/test-fixtures/suite6/smithy-build.json +++ b/test-fixtures/suite6/smithy-build.json @@ -1,3 +1,3 @@ { - "version": "1.0" + "version": "1.0" } diff --git a/tests/helper.ts b/tests/helper.ts index c73636a..6cd9f48 100644 --- a/tests/helper.ts +++ b/tests/helper.ts @@ -1,43 +1,43 @@ -import { TextDocument, TextEditor, Uri } from "vscode"; -import { resolve } from "path"; -import { glob } from "glob"; -import * as Mocha from "mocha"; +import { TextDocument, TextEditor, Uri } from 'vscode'; +import { resolve } from 'path'; +import { glob } from 'glob'; +import * as Mocha from 'mocha'; export let doc: TextDocument; export let editor: TextEditor; export const getDocPath = (p: string) => { - return resolve(__dirname, "../../test-fixtures", p); + return resolve(__dirname, '../../test-fixtures', p); }; export const getDocUri = (p: string) => { - return Uri.file(getDocPath(p)); + return Uri.file(getDocPath(p)); }; export async function waitForServerStartup() { - // Wait for Smithy Language Server to start - await new Promise((resolve) => setTimeout(resolve, 9000)); + // Wait for Smithy Language Server to start + await new Promise((resolve) => setTimeout(resolve, 9000)); } export function runTests(testsRoot: string, cb: (error: any, failures?: number) => void): void { - const mocha = new Mocha({ - ui: "tdd", - }); + const mocha = new Mocha({ + ui: 'tdd', + }); - glob("**/**.test.js", { cwd: testsRoot }) - .then((files) => { - files.forEach((f) => mocha.addFile(resolve(testsRoot, f))); + glob('**/**.test.js', { cwd: testsRoot }) + .then((files) => { + files.forEach((f) => mocha.addFile(resolve(testsRoot, f))); - try { - mocha.run((failures) => { - cb(null, failures); + try { + mocha.run((failures) => { + cb(null, failures); + }); + } catch (err) { + console.error(err); + cb(err); + } + }) + .catch((err) => { + return cb(err); }); - } catch (err) { - console.error(err); - cb(err); - } - }) - .catch((err) => { - return cb(err); - }); } diff --git a/tests/runTest.ts b/tests/runTest.ts index 47fc425..c07978f 100644 --- a/tests/runTest.ts +++ b/tests/runTest.ts @@ -1,74 +1,74 @@ -import { spawnSync } from "child_process"; -import { resolve } from "path"; +import { spawnSync } from 'child_process'; +import { resolve } from 'path'; import { - runTests, - downloadAndUnzipVSCode, - resolveCliPathFromVSCodeExecutablePath, - resolveCliArgsFromVSCodeExecutablePath, -} from "@vscode/test-electron"; -import * as assert from "assert"; + runTests, + downloadAndUnzipVSCode, + resolveCliPathFromVSCodeExecutablePath, + resolveCliArgsFromVSCodeExecutablePath, +} from '@vscode/test-electron'; +import * as assert from 'assert'; async function go() { - try { - const extensionDevelopmentPath = resolve(__dirname, "../../"); + try { + const extensionDevelopmentPath = resolve(__dirname, '../../'); - // Suite 1 - Extension registration and launching language server - await runTests({ - extensionDevelopmentPath, - extensionTestsPath: resolve(__dirname, "./suite1"), - launchArgs: [resolve(__dirname, "../../test-fixtures/suite1")], - }); + // Suite 1 - Extension registration and launching language server + await runTests({ + extensionDevelopmentPath, + extensionTestsPath: resolve(__dirname, './suite1'), + launchArgs: [resolve(__dirname, '../../test-fixtures/suite1')], + }); - // Suite 2 - Diagnostics from broken model - await runTests({ - extensionDevelopmentPath, - extensionTestsPath: resolve(__dirname, "./suite2"), - launchArgs: [resolve(__dirname, "../../test-fixtures/suite2")], - }); + // Suite 2 - Diagnostics from broken model + await runTests({ + extensionDevelopmentPath, + extensionTestsPath: resolve(__dirname, './suite2'), + launchArgs: [resolve(__dirname, '../../test-fixtures/suite2')], + }); - // Suite 3 - Selector commands - await runTests({ - extensionDevelopmentPath, - extensionTestsPath: resolve(__dirname, "./suite3"), - launchArgs: [resolve(__dirname, "../../test-fixtures/suite3")], - }); + // Suite 3 - Selector commands + await runTests({ + extensionDevelopmentPath, + extensionTestsPath: resolve(__dirname, './suite3'), + launchArgs: [resolve(__dirname, '../../test-fixtures/suite3')], + }); - // Suite 4 - User-specific root - await runTests({ - extensionDevelopmentPath, - extensionTestsPath: resolve(__dirname, "./suite4"), - launchArgs: [resolve(__dirname, "../../test-fixtures/suite4")], - }); + // Suite 4 - User-specific root + await runTests({ + extensionDevelopmentPath, + extensionTestsPath: resolve(__dirname, './suite4'), + launchArgs: [resolve(__dirname, '../../test-fixtures/suite4')], + }); - // Suite 5 - Formatter - await runTests({ - extensionDevelopmentPath, - extensionTestsPath: resolve(__dirname, "./suite5"), - launchArgs: [resolve(__dirname, "../../test-fixtures/suite5")], - }); + // Suite 5 - Formatter + await runTests({ + extensionDevelopmentPath, + extensionTestsPath: resolve(__dirname, './suite5'), + launchArgs: [resolve(__dirname, '../../test-fixtures/suite5')], + }); - // Suite 6 - Startup - await runTests({ - extensionDevelopmentPath, - extensionTestsPath: resolve(__dirname, "./suite6"), - launchArgs: [resolve(__dirname, "../../test-fixtures/suite6")], - }); + // Suite 6 - Startup + await runTests({ + extensionDevelopmentPath, + extensionTestsPath: resolve(__dirname, './suite6'), + launchArgs: [resolve(__dirname, '../../test-fixtures/suite6')], + }); - // Confirm that webpacked and vsce packaged extension can be installed. - const vscodeExecutablePath = await downloadAndUnzipVSCode(); - const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); + // Confirm that webpacked and vsce packaged extension can be installed. + const vscodeExecutablePath = await downloadAndUnzipVSCode(); + const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); - const result = spawnSync(cli, [...args, "--install-extension", "smithy-vscode.vsix", "--force"], { - encoding: "utf-8", - }); - assert.equal(result.status, 0); - assert.match(result.stdout, /Extension 'smithy-vscode.vsix' was successfully installed./); - } catch (err) { - console.error("Test Failure"); - console.log(err); - process.exit(1); - } + const result = spawnSync(cli, [...args, '--install-extension', 'smithy-vscode.vsix', '--force'], { + encoding: 'utf-8', + }); + assert.equal(result.status, 0); + assert.match(result.stdout, /Extension 'smithy-vscode.vsix' was successfully installed./); + } catch (err) { + console.error('Test Failure'); + console.log(err); + process.exit(1); + } } go(); diff --git a/tests/suite1/extension.test.ts b/tests/suite1/extension.test.ts index a77c4b5..3efd67a 100644 --- a/tests/suite1/extension.test.ts +++ b/tests/suite1/extension.test.ts @@ -1,32 +1,32 @@ -import * as assert from "assert"; -import * as vscode from "vscode"; -import { getDocUri, waitForServerStartup } from "./../helper"; +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { getDocUri, waitForServerStartup } from './../helper'; -suite("Extension tests", function () { - this.timeout(0); +suite('Extension tests', function () { + this.timeout(0); - test("Should start extension and Language Server", async () => { - const smithyMainUri = getDocUri("suite1/main.smithy"); - const doc = await vscode.workspace.openTextDocument(smithyMainUri); - const editor = await vscode.window.showTextDocument(doc); - const ext = vscode.extensions.getExtension("smithy.smithy-vscode-extension"); - await waitForServerStartup(); - const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); + test('Should start extension and Language Server', async () => { + const smithyMainUri = getDocUri('suite1/main.smithy'); + const doc = await vscode.workspace.openTextDocument(smithyMainUri); + const editor = await vscode.window.showTextDocument(doc); + const ext = vscode.extensions.getExtension('smithy.smithy-vscode-extension'); + await waitForServerStartup(); + const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); - // Grab model file directly - const modelFile = await vscode.workspace.openTextDocument(getDocUri("suite1/main.smithy")); - const modelFileText = modelFile.getText(); + // Grab model file directly + const modelFile = await vscode.workspace.openTextDocument(getDocUri('suite1/main.smithy')); + const modelFileText = modelFile.getText(); - assert.match(modelFileText, /namespace example.weather/); + assert.match(modelFileText, /namespace example.weather/); - assert.notEqual(doc, undefined); - assert.notEqual(editor, undefined); - assert.equal(ext.isActive, true); - assert.deepStrictEqual(diagnostics, []); - }); + assert.notEqual(doc, undefined); + assert.notEqual(editor, undefined); + assert.equal(ext.isActive, true); + assert.deepStrictEqual(diagnostics, []); + }); - test("Should register language", async () => { - const languages = await vscode.languages.getLanguages(); - assert.equal(languages.includes("smithy"), true); - }); + test('Should register language', async () => { + const languages = await vscode.languages.getLanguages(); + assert.equal(languages.includes('smithy'), true); + }); }); diff --git a/tests/suite1/index.ts b/tests/suite1/index.ts index 7b4a869..539deda 100644 --- a/tests/suite1/index.ts +++ b/tests/suite1/index.ts @@ -1,5 +1,5 @@ -import { runTests } from "../helper"; +import { runTests } from '../helper'; export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - runTests(testsRoot, cb); + runTests(testsRoot, cb); } diff --git a/tests/suite2/extension.test.ts b/tests/suite2/extension.test.ts index 70ab327..d3f0e10 100644 --- a/tests/suite2/extension.test.ts +++ b/tests/suite2/extension.test.ts @@ -1,20 +1,20 @@ -import * as assert from "assert"; -import * as vscode from "vscode"; -import { getDocUri, waitForServerStartup } from "./../helper"; +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { getDocUri, waitForServerStartup } from './../helper'; -suite("broken model tests", function () { - this.timeout(0); +suite('broken model tests', function () { + this.timeout(0); - test("Should provide diagnostics", async () => { - const smithyMainUri = getDocUri("suite2/main.smithy"); - const doc = await vscode.workspace.openTextDocument(smithyMainUri); - await vscode.window.showTextDocument(doc); - await waitForServerStartup(); - const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); + test('Should provide diagnostics', async () => { + const smithyMainUri = getDocUri('suite2/main.smithy'); + const doc = await vscode.workspace.openTextDocument(smithyMainUri); + await vscode.window.showTextDocument(doc); + await waitForServerStartup(); + const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); - assert.match(diagnostics[0].message, /Cannot apply `smithy.api#deprecated` to an immutable prelude shape/); - assert.equal(diagnostics[0].range.start.line, 4); - assert.equal(diagnostics[0].range.start.character, 24); - return Promise.resolve(); - }); + assert.match(diagnostics[0].message, /Cannot apply `smithy.api#deprecated` to an immutable prelude shape/); + assert.equal(diagnostics[0].range.start.line, 4); + assert.equal(diagnostics[0].range.start.character, 24); + return Promise.resolve(); + }); }); diff --git a/tests/suite2/index.ts b/tests/suite2/index.ts index 7b4a869..539deda 100644 --- a/tests/suite2/index.ts +++ b/tests/suite2/index.ts @@ -1,5 +1,5 @@ -import { runTests } from "../helper"; +import { runTests } from '../helper'; export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - runTests(testsRoot, cb); + runTests(testsRoot, cb); } diff --git a/tests/suite3/extension.test.ts b/tests/suite3/extension.test.ts index e1353b8..9f6e306 100644 --- a/tests/suite3/extension.test.ts +++ b/tests/suite3/extension.test.ts @@ -1,22 +1,22 @@ -import * as vscode from "vscode"; -import { getDocUri, waitForServerStartup } from "./../helper"; -import * as sinon from "sinon"; +import * as vscode from 'vscode'; +import { getDocUri, waitForServerStartup } from './../helper'; +import * as sinon from 'sinon'; -suite("Selector tests", function () { - this.timeout(0); +suite('Selector tests', function () { + this.timeout(0); - test("Can run selectors", async () => { - const smithyMainUri = getDocUri("suite3/main.smithy"); - const doc = await vscode.workspace.openTextDocument(smithyMainUri); - await vscode.window.showTextDocument(doc); - await waitForServerStartup(); + test('Can run selectors', async () => { + const smithyMainUri = getDocUri('suite3/main.smithy'); + const doc = await vscode.workspace.openTextDocument(smithyMainUri); + await vscode.window.showTextDocument(doc); + await waitForServerStartup(); - const showInputBox = sinon.stub(vscode.window, "showInputBox"); - showInputBox.resolves("operation [id|namespace=example.weather]"); - await vscode.commands.executeCommand("smithy.runSelector"); - // we don't have a way to check the output. as long as this command - // can run it should be fine - more robust tests are done on the server - // side. - return Promise.resolve(); - }); + const showInputBox = sinon.stub(vscode.window, 'showInputBox'); + showInputBox.resolves('operation [id|namespace=example.weather]'); + await vscode.commands.executeCommand('smithy.runSelector'); + // we don't have a way to check the output. as long as this command + // can run it should be fine - more robust tests are done on the server + // side. + return Promise.resolve(); + }); }); diff --git a/tests/suite3/index.ts b/tests/suite3/index.ts index 7b4a869..539deda 100644 --- a/tests/suite3/index.ts +++ b/tests/suite3/index.ts @@ -1,5 +1,5 @@ -import { runTests } from "../helper"; +import { runTests } from '../helper'; export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - runTests(testsRoot, cb); + runTests(testsRoot, cb); } diff --git a/tests/suite4/extension.test.ts b/tests/suite4/extension.test.ts index 4d0ee7a..9aa7f3e 100644 --- a/tests/suite4/extension.test.ts +++ b/tests/suite4/extension.test.ts @@ -1,19 +1,19 @@ -import * as assert from "assert"; -import * as vscode from "vscode"; -import { getDocUri, waitForServerStartup } from "../helper"; +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { getDocUri, waitForServerStartup } from '../helper'; -suite("User-specific root", function () { - this.timeout(0); +suite('User-specific root', function () { + this.timeout(0); - test("Should download jars even when not in workspace root", async () => { - const smithyMainUri = getDocUri("suite4/smithy/main.smithy"); - const doc = await vscode.workspace.openTextDocument(smithyMainUri); - await vscode.window.showTextDocument(doc); - await waitForServerStartup(); - const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); + test('Should download jars even when not in workspace root', async () => { + const smithyMainUri = getDocUri('suite4/smithy/main.smithy'); + const doc = await vscode.workspace.openTextDocument(smithyMainUri); + await vscode.window.showTextDocument(doc); + await waitForServerStartup(); + const diagnostics = vscode.languages.getDiagnostics(smithyMainUri); - // We would have diagnostics for unknown traits if the jars weren't downloaded - assert.equal(diagnostics.length, 0); - return Promise.resolve(); - }); + // We would have diagnostics for unknown traits if the jars weren't downloaded + assert.equal(diagnostics.length, 0); + return Promise.resolve(); + }); }); diff --git a/tests/suite4/index.ts b/tests/suite4/index.ts index 7b4a869..539deda 100644 --- a/tests/suite4/index.ts +++ b/tests/suite4/index.ts @@ -1,5 +1,5 @@ -import { runTests } from "../helper"; +import { runTests } from '../helper'; export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - runTests(testsRoot, cb); + runTests(testsRoot, cb); } diff --git a/tests/suite5/extension.test.ts b/tests/suite5/extension.test.ts index 07a764d..b28f181 100644 --- a/tests/suite5/extension.test.ts +++ b/tests/suite5/extension.test.ts @@ -1,20 +1,20 @@ -import * as assert from "assert"; -import * as vscode from "vscode"; -import { getDocUri, waitForServerStartup } from "../helper"; +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { getDocUri, waitForServerStartup } from '../helper'; -suite("formatting tests", function () { - this.timeout(0); +suite('formatting tests', function () { + this.timeout(0); - test("Should register Smithy formatter", async () => { - const smithyMainUri = getDocUri("suite5/smithy/main.smithy"); - const doc = await vscode.workspace.openTextDocument(smithyMainUri); - await vscode.window.showTextDocument(doc); - await waitForServerStartup(); - const edits: vscode.TextEdit[] = await vscode.commands.executeCommand( - "vscode.executeFormatDocumentProvider", - smithyMainUri - ); - assert.strictEqual(edits.length > 0, true, "expected edits from formatter, but got none"); - return Promise.resolve(); - }); + test('Should register Smithy formatter', async () => { + const smithyMainUri = getDocUri('suite5/smithy/main.smithy'); + const doc = await vscode.workspace.openTextDocument(smithyMainUri); + await vscode.window.showTextDocument(doc); + await waitForServerStartup(); + const edits: vscode.TextEdit[] = await vscode.commands.executeCommand( + 'vscode.executeFormatDocumentProvider', + smithyMainUri + ); + assert.strictEqual(edits.length > 0, true, 'expected edits from formatter, but got none'); + return Promise.resolve(); + }); }); diff --git a/tests/suite5/index.ts b/tests/suite5/index.ts index 7b4a869..539deda 100644 --- a/tests/suite5/index.ts +++ b/tests/suite5/index.ts @@ -1,5 +1,5 @@ -import { runTests } from "../helper"; +import { runTests } from '../helper'; export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - runTests(testsRoot, cb); + runTests(testsRoot, cb); } diff --git a/tests/suite6/extension.test.ts b/tests/suite6/extension.test.ts index 1c931c8..2011f72 100644 --- a/tests/suite6/extension.test.ts +++ b/tests/suite6/extension.test.ts @@ -1,13 +1,13 @@ -import * as assert from "assert"; -import * as vscode from "vscode"; +import * as assert from 'assert'; +import * as vscode from 'vscode'; -suite("Startup", function () { - this.timeout(0); +suite('Startup', function () { + this.timeout(0); - test("Should start without opening a smithy file", async () => { - const extension = vscode.extensions.getExtension("smithy.smithy-vscode-extension"); - assert.ok(extension.isActive); + test('Should start without opening a smithy file', async () => { + const extension = vscode.extensions.getExtension('smithy.smithy-vscode-extension'); + assert.ok(extension.isActive); - return Promise.resolve(); - }); + return Promise.resolve(); + }); }); diff --git a/tests/suite6/index.ts b/tests/suite6/index.ts index 7b4a869..539deda 100644 --- a/tests/suite6/index.ts +++ b/tests/suite6/index.ts @@ -1,5 +1,5 @@ -import { runTests } from "../helper"; +import { runTests } from '../helper'; export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - runTests(testsRoot, cb); + runTests(testsRoot, cb); } diff --git a/tsconfig.json b/tsconfig.json index ccecc55..42490f3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,12 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "ES2019", - "outDir": "out", - "lib": ["ES2019"], - "sourceMap": true, - "skipLibCheck": true - }, - "include": ["src", "tests"], - "exclude": ["node_modules", ".vscode-test"] + "compilerOptions": { + "module": "commonjs", + "target": "ES2019", + "outDir": "out", + "lib": ["ES2019"], + "sourceMap": true, + "skipLibCheck": true + }, + "include": ["src", "tests"], + "exclude": ["node_modules", ".vscode-test"] } diff --git a/webpack.config.js b/webpack.config.js index ff9e0f7..e75ea95 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,39 +1,39 @@ //@ts-check -"use strict"; +'use strict'; -const path = require("path"); +const path = require('path'); /**@type {import('webpack').Configuration}*/ const config = { - target: "node", - mode: "none", // Set to 'production' when packaging + target: 'node', + mode: 'none', // Set to 'production' when packaging - entry: "./src/extension.ts", - output: { - path: path.resolve(__dirname, "out", "src"), - filename: "extension.js", - libraryTarget: "commonjs2", - }, - devtool: "nosources-source-map", - externals: { - vscode: "commonjs vscode", // vscode module provided by VS Code itself. - }, - resolve: { - extensions: [".ts", ".js"], - }, - module: { - rules: [ - { - test: /\.ts$/, - exclude: /node_modules/, - use: [ - { - loader: "ts-loader", - }, + entry: './src/extension.ts', + output: { + path: path.resolve(__dirname, 'out', 'src'), + filename: 'extension.js', + libraryTarget: 'commonjs2', + }, + devtool: 'nosources-source-map', + externals: { + vscode: 'commonjs vscode', // vscode module provided by VS Code itself. + }, + resolve: { + extensions: ['.ts', '.js'], + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: [ + { + loader: 'ts-loader', + }, + ], + }, ], - }, - ], - }, + }, }; module.exports = config;