├── .eslintrc.json ├── .github ├── funding.yml └── workflows │ └── release.yml ├── .gitignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── README.md ├── documentation └── preview.png ├── package.json ├── snippets └── dynamodb.json ├── src ├── extension.ts ├── previewContentProvider.ts ├── providers │ ├── AppsyncSignatureHelpProvider.ts │ ├── allTypes.ts │ ├── context │ │ ├── arguments.ts │ │ ├── identity.ts │ │ ├── index.ts │ │ ├── info.ts │ │ ├── source.ts │ │ └── stash.ts │ ├── dataTypes.d.ts │ ├── index.ts │ ├── standard │ │ └── map.ts │ └── util │ │ ├── dynamodb.ts │ │ ├── index.ts │ │ ├── list.ts │ │ ├── map.ts │ │ └── time.ts └── test │ ├── runTest.ts │ └── suite │ ├── extension.test.ts │ └── index.ts ├── test_templates └── dynamo.vtl ├── tsconfig.json ├── vsc-extension-quickstart.md ├── yarn-error.log └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | issuehunt: thebenforce 2 | ko_fi: thebenforce 3 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | release: 8 | name: Release 9 | runs-on: ubuntu-18.04 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v1 13 | - name: Setup Node.js 14 | uses: actions/setup-node@v1 15 | with: 16 | node-version: 12 17 | - name: Install dependencies 18 | run: yarn install 19 | - name: Release 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | VSCE_TOKEN: ${{ secrets.VSCE_TOKEN }} 23 | run: yarn semantic-release 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it 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": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "${defaultBuildTask}" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "${defaultBuildTask}" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.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 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | documentation/** 6 | .gitignore 7 | vsc-extension-quickstart.md 8 | **/tsconfig.json 9 | **/.eslintrc.json 10 | **/*.map 11 | **/*.ts 12 | test_templates/** 13 | .github/** -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # appsync-resolver-autocomplete README 2 | 3 | Adds autocomplete support for AppSync resolver templates when editing .vtl files. 4 | 5 | ![Release Workflow Status](https://img.shields.io/github/workflow/status/theBenForce/vscode-appsync-resolver-autocomplete/Release) 6 | [![Visual Studio Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/thebenforce.appsync-resolver-autocomplete)](https://marketplace.visualstudio.com/items?itemName=theBenForce.appsync-resolver-autocomplete) 7 | [![Maintainability](https://api.codeclimate.com/v1/badges/c815baac0a3da72636d0/maintainability)](https://codeclimate.com/github/theBenForce/vscode-appsync-resolver-autocomplete/maintainability) 8 | 9 | ![Preview](https://raw.githubusercontent.com/theBenForce/vscode-appsync-resolver-autocomplete/master/documentation/preview.png "Autocomplete preview") 10 | 11 | ## References 12 | 13 | - [Completions Sample](https://github.com/microsoft/vscode-extension-samples/blob/master/completions-sample/src/extension.ts) 14 | - [Resolver Mapping Template Reference](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference.html) 15 | -------------------------------------------------------------------------------- /documentation/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theBenForce/vscode-appsync-resolver-autocomplete/059ed0323a11fc5d23ad5b4b5ea69dbd39c3c32c/documentation/preview.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appsync-resolver-autocomplete", 3 | "publisher": "theBenForce", 4 | "displayName": "AppSync Resolver Autocomplete", 5 | "description": "Autocomplete functionality when editing AWS AppSync resolver vtl files.", 6 | "version": "0.0.1", 7 | "engines": { 8 | "vscode": "^1.49.0" 9 | }, 10 | "repository": { 11 | "type": "git+ssh", 12 | "url": "git@github.com:theBenForce/vscode-appsync-resolver-autocomplete.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/theBenForce/vscode-appsync-resolver-autocomplete/issues" 16 | }, 17 | "categories": [ 18 | "Other", 19 | "Snippets" 20 | ], 21 | "activationEvents": [ 22 | "onLanguage:velocity", 23 | "onCommand:appsyncVtl.showPreview" 24 | ], 25 | "contributes": { 26 | "snippets": [ 27 | { 28 | "language": "velocity", 29 | "path": "./snippets/dynamodb.json" 30 | } 31 | ], 32 | "signatureHelpProvider": { 33 | "triggerCharacters": [ 34 | "(" 35 | ] 36 | }, 37 | "commands": [ 38 | { 39 | "command": "appsyncVtl.showPreview", 40 | "title": "AppSync Resolver: Velocity Preview" 41 | } 42 | ], 43 | "menus": { 44 | "editor/title": [ 45 | { 46 | "command": "appsyncVtl.showPreview", 47 | "when": "resourceLangId == velocity", 48 | "group": "navigation" 49 | } 50 | ] 51 | } 52 | }, 53 | "main": "./out/extension.js", 54 | "release": { 55 | "branches": [ 56 | "master" 57 | ], 58 | "plugins": [ 59 | "@semantic-release/commit-analyzer", 60 | "@semantic-release/release-notes-generator", 61 | [ 62 | "@semantic-release/changelog", 63 | { 64 | "changelogTitle": "# appsync-resolver-autocomplete Change Log", 65 | "changelogFile": "CHANGELOG.md" 66 | } 67 | ], 68 | "semantic-release-vsce", 69 | [ 70 | "@semantic-release/github", 71 | { 72 | "assets": [ 73 | { 74 | "path": "CHANGELOG.md", 75 | "label": "Changelog" 76 | }, 77 | { 78 | "path": "appsync-resolver-autocomplete.vsix", 79 | "label": "VSCode Extension Package" 80 | } 81 | ] 82 | } 83 | ] 84 | ], 85 | "verifyConditions": [ 86 | "semantic-release-vsce", 87 | "@semantic-release/github" 88 | ], 89 | "prepare": [ 90 | "@semantic-release/changelog", 91 | { 92 | "path": "semantic-release-vsce", 93 | "packageVsix": "appsync-resolver-autocomplete.vsix" 94 | } 95 | ], 96 | "publish": [ 97 | "semantic-release-vsce", 98 | { 99 | "path": "@semantic-release/github", 100 | "assets": "appsync-resolver-autocomplete.vsix" 101 | } 102 | ] 103 | }, 104 | "scripts": { 105 | "vscode:prepublish": "yarn run compile", 106 | "compile": "tsc -p ./", 107 | "lint": "eslint src --ext ts", 108 | "watch": "tsc -watch -p ./", 109 | "pretest": "yarn run compile && yarn run lint", 110 | "test": "node ./out/test/runTest.js" 111 | }, 112 | "config": { 113 | "commitizen": { 114 | "path": "./node_modules/cz-conventional-changelog" 115 | } 116 | }, 117 | "devDependencies": { 118 | "@semantic-release/changelog": "^5.0.1", 119 | "@semantic-release/commit-analyzer": "^8.0.1", 120 | "@semantic-release/github": "^7.1.1", 121 | "@semantic-release/release-notes-generator": "^9.0.1", 122 | "@types/glob": "^7.1.3", 123 | "@types/mocha": "^8.0.3", 124 | "@types/node": "^14.11.1", 125 | "@types/vscode": "^1.49.0", 126 | "@typescript-eslint/eslint-plugin": "^4.1.1", 127 | "@typescript-eslint/parser": "^4.1.1", 128 | "commitizen": "^4.2.1", 129 | "cz-conventional-changelog": "^3.3.0", 130 | "eslint": "^7.9.0", 131 | "glob": "^7.1.6", 132 | "mocha": "^8.1.3", 133 | "prettier": "^2.1.2", 134 | "semantic-release": "^17.2.3", 135 | "semantic-release-vsce": "^3.0.1", 136 | "typescript": "^4.0.2", 137 | "vsce": "^1.79.5", 138 | "vscode-test": "^1.4.0" 139 | }, 140 | "dependencies": { 141 | "appsync-template-tester": "^1.0.9", 142 | "aws-sdk": "^2.755.0" 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /snippets/dynamodb.json: -------------------------------------------------------------------------------- 1 | { 2 | "DynamoGetItemRequest": { 3 | "prefix": "getItemRequest", 4 | "description": "The `GetItem` request mapping document lets you tell the AWS AppSync DynamoDB resolver to make a GetItem request to DynamoDB.", 5 | "body": [ 6 | "{", 7 | " \"version\" : \"2017-02-28\",", 8 | " \"operation\" : \"GetItem\",", 9 | " \"key\" : {", 10 | " \"$1\": ${2:\\$util.dynamodb.toDynamoDB($3)},", 11 | " \"$4\": ${5:\\$util.dynamodb.toDynamoDB($6)}", 12 | " },", 13 | " \"consistentRead\" : true", 14 | "}" 15 | ] 16 | }, 17 | "DynamoPutItemRequest": { 18 | "prefix": "putItemRequest", 19 | "description": "The PutItem request mapping document lets you tell the AWS AppSync DynamoDB resolver to make a PutItem request to DynamoDB.", 20 | "body": [ 21 | "$LINE_COMMENT Reference: https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html#aws-appsync-resolver-mapping-template-reference-dynamodb-putitem", 22 | "{", 23 | " \"version\" : \"2018-05-29\",", 24 | " \"operation\" : \"PutItem\",", 25 | " \"key\" : {", 26 | " \"$1\": ${2:\\$util.dynamodb.toDynamoDB($3)},", 27 | " \"$4\": ${5:\\$util.dynamodb.toDynamoDB($6)}", 28 | " },", 29 | " \"attributeValues\" : {", 30 | " $7", 31 | " },", 32 | " $LINE_COMMENT A condition to determine if the request should succeed or not, based on the state of the object already in DynamoDB.", 33 | " \"condition\" : {", 34 | " $8", 35 | " },", 36 | " $LINE_COMMENT A numeric value that represents the latest known version of an item. This value is optional. This field is used for Conflict Detection and is only supported on versioned data sources.", 37 | " \"_version\" : 1", 38 | "}" 39 | ] 40 | } 41 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as vscode from "vscode"; 4 | 5 | import registerProviders from "./providers"; 6 | import { VelocityPreviewProvider } from "./previewContentProvider"; 7 | 8 | // this method is called when your extension is activated 9 | // your extension is activated the very first time the command is executed 10 | export function activate(context: vscode.ExtensionContext) { 11 | console.info(`appsync resolver extension activated!`); 12 | 13 | registerProviders(context); 14 | VelocityPreviewProvider.register(context); 15 | } 16 | 17 | // this method is called when your extension is deactivated 18 | export function deactivate() {} 19 | -------------------------------------------------------------------------------- /src/previewContentProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { Converter } from "aws-sdk/clients/dynamodb"; 3 | import Parser from "appsync-template-tester"; 4 | 5 | function isVelocityFile(document?: vscode.TextDocument): boolean { 6 | return document?.languageId === "velocity"; 7 | } 8 | 9 | export class VelocityPreviewProvider 10 | implements vscode.TextDocumentContentProvider { 11 | onDidChangeEmitter = new vscode.EventEmitter(); 12 | onDidChange = this.onDidChangeEmitter.event; 13 | 14 | private contentProviderRegistration: vscode.Disposable; 15 | 16 | static SCHEME = `appsyncvtl`; 17 | static URI = vscode.Uri.parse( 18 | `${VelocityPreviewProvider.SCHEME}:preview.json`, 19 | true 20 | ); 21 | 22 | constructor() { 23 | this.contentProviderRegistration = vscode.workspace.registerTextDocumentContentProvider( 24 | VelocityPreviewProvider.SCHEME, 25 | this 26 | ); 27 | } 28 | 29 | provideTextDocumentContent( 30 | uri: vscode.Uri, 31 | token: vscode.CancellationToken 32 | ): vscode.ProviderResult { 33 | const editor = vscode.window.activeTextEditor; 34 | 35 | if (!isVelocityFile(editor?.document)) { 36 | console.error(`Wrong document type`); 37 | return `Unknown document type "${editor?.document?.languageId}"`; 38 | } 39 | 40 | const content = editor?.document?.getText() ?? ``; 41 | 42 | const parser = new Parser(content.replace(/""/g, `\\"`)); 43 | 44 | return parser.resolve({}); 45 | } 46 | 47 | async onContentUpdated( 48 | event?: vscode.TextDocumentChangeEvent | vscode.TextEditor 49 | ) { 50 | if (!event) { 51 | return; 52 | } 53 | 54 | if (isVelocityFile(event.document)) { 55 | this.onDidChangeEmitter.fire(VelocityPreviewProvider.URI); 56 | } 57 | } 58 | 59 | static register(context: vscode.ExtensionContext): VelocityPreviewProvider { 60 | const provider = new VelocityPreviewProvider(); 61 | 62 | context.subscriptions.push( 63 | vscode.workspace.onDidChangeTextDocument( 64 | provider.onContentUpdated.bind(provider) 65 | ) 66 | ); 67 | context.subscriptions.push( 68 | vscode.window.onDidChangeActiveTextEditor( 69 | provider.onContentUpdated.bind(provider) 70 | ) 71 | ); 72 | 73 | vscode.commands.registerCommand("appsyncVtl.showPreview", async () => { 74 | let doc = await vscode.workspace.openTextDocument(this.URI); 75 | await vscode.window.showTextDocument(doc, { 76 | preview: false, 77 | viewColumn: vscode.ViewColumn.Beside, 78 | preserveFocus: true, 79 | }); 80 | }); 81 | 82 | return provider; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/providers/AppsyncSignatureHelpProvider.ts: -------------------------------------------------------------------------------- 1 | import { SignatureHelpProvider, TextDocument, Position, CancellationToken, SignatureHelp, MarkdownString, SignatureInformation, CompletionItemKind } from "vscode"; 2 | 3 | import allTypes from "./allTypes"; 4 | 5 | export class AppsyncSignatureHelpProvider implements SignatureHelpProvider { 6 | _methodReference: Record> = {}; 7 | constructor() { 8 | allTypes.forEach((itemSettings) => { 9 | itemSettings.prefixes.forEach(prefix => { 10 | itemSettings.properties.filter(prop => prop.kind === CompletionItemKind.Method) 11 | .forEach(prop => { 12 | prop.names.forEach(name => { 13 | this._methodReference[`${prefix}${name}`] = prop.signatures?.map(sig => { 14 | sig.documentation = sig.documentation ?? prop.documentation; 15 | sig.label = sig.label ?? `${name}()`; 16 | return sig; 17 | }) ?? [ 18 | { 19 | label: `${name}()`, 20 | documentation: new MarkdownString(prop.documentation), 21 | parameters: [] 22 | } 23 | ]; 24 | }); 25 | }); 26 | }); 27 | }); 28 | } 29 | 30 | public async provideSignatureHelp( 31 | document: TextDocument, position: Position, token: CancellationToken): 32 | Promise { 33 | 34 | let linePrefix = document.lineAt(position).text.substr(0, position.character); 35 | let methodName = linePrefix.substring(0, linePrefix.lastIndexOf("(")); 36 | let commaCount = linePrefix.substring(methodName.length).split(",").length - 1; 37 | 38 | if (token.isCancellationRequested || linePrefix.endsWith(")")) { return undefined; } 39 | 40 | 41 | const methodRef = Object.entries(this._methodReference).find(([key]) => methodName.endsWith(key))?.[1]; 42 | 43 | if (!methodRef) { 44 | return undefined; 45 | } 46 | 47 | const result = new SignatureHelp(); 48 | 49 | result.signatures = methodRef; 50 | 51 | result.activeSignature = Math.max(0, methodRef.findIndex(value => value.parameters.length > commaCount)); 52 | result.activeParameter = commaCount; 53 | 54 | return result; 55 | } 56 | } -------------------------------------------------------------------------------- /src/providers/allTypes.ts: -------------------------------------------------------------------------------- 1 | 2 | import context from "./context"; 3 | import util from "./util"; 4 | 5 | export default [ 6 | ...context, 7 | ...util 8 | ]; -------------------------------------------------------------------------------- /src/providers/context/arguments.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import map from "../standard/map"; 3 | 4 | export default [{ 5 | prefixes: ['$ctx.args.', '$context.args.', '$ctx.arguments.', '$context.arguments.'], 6 | properties: [ 7 | ...map 8 | ] 9 | }] as Array; -------------------------------------------------------------------------------- /src/providers/context/identity.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import { CompletionItemKind } from "vscode"; 3 | 4 | export default [{ 5 | prefixes: ['$ctx.identity.', '$context.identity.'], 6 | properties: [ 7 | { names: ['accountId'], kind: CompletionItemKind.Property, documentation: "The AWS account ID of the caller." }, 8 | { names: ['claims'], documentation: 'The claims that the user has.' }, 9 | { names: ['cognitoIdentityAuthType'], kind: CompletionItemKind.Property, documentation: 'Either `authenticated` or `unauthenticated` based on the identity type.' }, 10 | { names: ['cognitoIdentityAuthProvider'], kind: CompletionItemKind.Property, documentation: "The external identity provider that was used to obtain the credentials used to sign the request." }, 11 | { names: ['cognitoIdentityId'], kind: CompletionItemKind.Property, documentation: 'The Amazon Cognito identity ID of the caller.' }, 12 | { names: ['cognitoIdentityPoolId'], kind: CompletionItemKind.Property, documentation: 'The Amazon Cognito identity pool ID associated with the caller.' }, 13 | { names: ['defaultAuthStrategy'], kind: CompletionItemKind.Property, documentation: 'The default authorization strategy for this caller (`ALLOW` or `DENY`).' }, 14 | { names: ['issuer'], kind: CompletionItemKind.Property, documentation: 'The token issuer.' }, 15 | { names: ['sourceIp'], kind: CompletionItemKind.Property, documentation: 'The source IP address of the caller received by AWS AppSync. If the request doesn’t include the `x-forwarded-for header`, the source IP value contains only a single IP address from the TCP connection. If the request includes a `x-forwarded-for header`, the source IP is a list of IP addresses from the `x-forwarded-for header`, in addition to the IP address from the TCP connection.' }, 16 | { names: ['sub'], kind: CompletionItemKind.Property, documentation: 'The UUID of the authenticated user.' }, 17 | { names: ['user'], kind: CompletionItemKind.Property, documentation: 'The IAM user.' }, 18 | { names: ['userArn'], kind: CompletionItemKind.Property, documentation: 'The ARN of the IAM user.' }, 19 | { names: ['username'], kind: CompletionItemKind.Property, documentation: 'The user name of the authenticated user. In the case of `AMAZON_COGNITO_USER_POOLS` authorization, the value of *username* is the value of attribute *cognito:username*. In the case of `AWS_IAM` authorization, the value of *username* is the value of the AWS user principal. We recommend that you use `cognitoIdentityId` if you’re using *AWS IAM* authorization with credentials vended from Amazon Cognito identity pools.' } 20 | ] 21 | }] as Array; -------------------------------------------------------------------------------- /src/providers/context/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { AutocompleteData } from '../dataTypes'; 3 | import identity from "./identity"; 4 | import info from "./info"; 5 | import args from './arguments'; 6 | import source from './source'; 7 | import stash from './stash'; 8 | 9 | export default [ 10 | { 11 | prefixes: ['$ctx.', '$context.'], 12 | properties: [ 13 | { names: ["arguments", "args"], documentation: "A map that contains all GraphQL arguments for this field." }, 14 | { names: ["identity"], documentation: "An object that contains information about the caller." }, 15 | { names: ["source"], documentation: "A map that contains the resolution of the parent field." }, 16 | { names: ["stash"], documentation: "The stash is a map that is made available inside each resolver and function mapping template. The same stash instance lives through a single resolver execution. This means that you can use the stash to pass arbitrary data across request and response mapping templates, and across functions in a pipeline resolver. The stash exposes the same methods as the Java Map data structure." }, 17 | { names: ["result"], documentation: "A container for the results of this resolver. This field is only available to response mapping templates." }, 18 | { names: ["prev.result"], documentation: "It represents the result of whatever previous operation was executed in a pipeline resolver. If the previous operation was the pipeline resolver request mapping template, then `$ctx.prev.result` represents the output of the evaluation of the template, and is made available to the first function in the pipeline. If the previous operation was the first function, then `$ctx.prev.result` represents the output of the first function, and is made available to the second function in the pipeline. If the previous operation was the last function, then `$ctx.prev.result` represents the output of the first function, and is made available to the pipeline resolver response mapping template." }, 19 | { names: ["info"], documentation: "An object that contains information about the GraphQL request." } 20 | ] 21 | }, 22 | ...identity, 23 | ...info, 24 | ...args, 25 | ...source, 26 | ...stash, 27 | ] as Array; -------------------------------------------------------------------------------- /src/providers/context/info.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import { CompletionItemKind } from "vscode"; 3 | 4 | export default [{ 5 | prefixes: ['$ctx.info.', '$context.info.'], 6 | properties: [ 7 | { names: ['fieldName'], kind: CompletionItemKind.Property, documentation: "The name of the field that is currently being resolved." }, 8 | { names: ['parentTypeName'], kind: CompletionItemKind.Property, documentation: "The name of the parent type for the field that is currently being resolved." }, 9 | { names: ['variables'], kind: CompletionItemKind.Property, documentation: "A map which holds all variables that are passed into the GraphQL request." }, 10 | { names: ['selectionSetList'], kind: CompletionItemKind.Property, documentation: "A list representation of the fields in the GraphQL selection set. Fields that are aliased will only be referenced by the alias name, not the field name. The following example shows this in detail." }, 11 | { names: ['selectionSetGraphQL'], kind: CompletionItemKind.Property, documentation: "A string representation of the selection set, formatted as GraphQL schema definition language (SDL). Although fragments aren’t be merged into the selection set, inline fragments are preserved." }, 12 | ] 13 | }] as Array; -------------------------------------------------------------------------------- /src/providers/context/source.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import map from "../standard/map"; 3 | 4 | export default [{ 5 | prefixes: ['$ctx.source.', '$context.source.'], 6 | properties: [ 7 | ...map 8 | ] 9 | }] as Array; -------------------------------------------------------------------------------- /src/providers/context/stash.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import map from "../standard/map"; 3 | 4 | export default [{ 5 | prefixes: ['$ctx.stash.', '$context.stash.'], 6 | properties: [ 7 | ...map 8 | ] 9 | }] as Array; -------------------------------------------------------------------------------- /src/providers/dataTypes.d.ts: -------------------------------------------------------------------------------- 1 | import { CompletionItemKind, SignatureInformation } from "vscode"; 2 | 3 | declare module AutocompleteData { 4 | export interface Item { 5 | names: Array; 6 | documentation: string; 7 | kind?: CompletionItemKind; 8 | signatures?: Array; 9 | } 10 | 11 | export interface CompletionItemSettings { 12 | prefixes: Array; 13 | properties: Array; 14 | } 15 | } -------------------------------------------------------------------------------- /src/providers/index.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import allTypes from "./allTypes"; 3 | import { AutocompleteData } from "./dataTypes"; 4 | import { AppsyncSignatureHelpProvider } from "./AppsyncSignatureHelpProvider"; 5 | 6 | const ROOT_PROPERTIES = [ 7 | { names: ['context', 'ctx'], documentation: "The [`$context`](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#accessing-the-context) variable is a map that holds all of the contextual information for your resolver invocation." }, 8 | { names: ['util'], documentation: 'The [`$util`](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#utility-helpers-in-util) variable contains general utility methods that make it easier to work with data.' } 9 | ] as Array; 10 | 11 | const register = (item: AutocompleteData.CompletionItemSettings) => vscode.languages.registerCompletionItemProvider( 12 | 'velocity', 13 | { 14 | provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) { 15 | let linePrefix = document.lineAt(position).text.substr(0, position.character); 16 | if (item.prefixes.find(x => linePrefix.endsWith(x))) { 17 | return item.properties.map(property => property.names.map(label => { 18 | 19 | const result = new vscode.CompletionItem(label, property.kind ?? vscode.CompletionItemKind.Module); 20 | result.documentation = new vscode.MarkdownString(property.documentation); 21 | if (property.kind === vscode.CompletionItemKind.Method) { 22 | result.commitCharacters = ['(']; 23 | // result.insertText = `${label}()`; 24 | } else { 25 | result.commitCharacters = ['.']; 26 | } 27 | return result; 28 | }) 29 | ).reduce((result, next) => result.concat(next), []); 30 | } 31 | 32 | 33 | 34 | return undefined; 35 | } 36 | }, 37 | '.' // triggered whenever a '.' is being typed 38 | ); 39 | 40 | export default (ctx: vscode.ExtensionContext) => { 41 | 42 | ctx.subscriptions.push( 43 | vscode.languages.registerSignatureHelpProvider( 44 | 'velocity', new AppsyncSignatureHelpProvider(), '(', ',')); 45 | 46 | vscode.languages.registerCompletionItemProvider( 47 | 'velocity', 48 | { 49 | provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) { 50 | let linePrefix = document.lineAt(position).text.substr(0, position.character); 51 | if (!linePrefix.endsWith('$')) { 52 | return undefined; 53 | } 54 | 55 | return ROOT_PROPERTIES.map(property => { 56 | const results = property.names.map(label => { 57 | const result = new vscode.CompletionItem(label, property.kind ?? vscode.CompletionItemKind.Module); 58 | result.documentation = new vscode.MarkdownString(property.documentation); 59 | return result; 60 | }); 61 | return results; 62 | }).reduce((result, next) => result.concat(next), []); 63 | } 64 | }, 65 | '$' // triggered whenever a '$' is being typed 66 | ); 67 | 68 | allTypes.forEach(register); 69 | }; -------------------------------------------------------------------------------- /src/providers/standard/map.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from '../dataTypes'; 2 | import { CompletionItemKind } from 'vscode'; 3 | 4 | /** 5 | * Methods defined by the Java [Map](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html) class 6 | */ 7 | export default [ 8 | { 9 | names: ["clear"], kind: CompletionItemKind.Method, documentation: "Removes all of the mappings from this map (optional operation)." 10 | }, 11 | { 12 | names: ["containsKey"], kind: CompletionItemKind.Method, documentation: "Returns true if this map contains a mapping for the specified key.", 13 | signatures: [ 14 | { 15 | label: 'boolean containsKey(Object key)', 16 | parameters: [ 17 | { label: 'key', documentation: 'key whose presence in this map is to be tested' } 18 | ] 19 | } 20 | ] 21 | }, 22 | { names: ["containsValue"], kind: CompletionItemKind.Method, documentation: "Returns true if this map maps one or more keys to the specified value." }, 23 | { names: ["entrySet"], kind: CompletionItemKind.Method, documentation: "Returns a Set view of the mappings contained in this map." }, 24 | { names: ["get"], kind: CompletionItemKind.Method, documentation: "Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key." }, 25 | { names: ["getOrDefault"], kind: CompletionItemKind.Method, documentation: "Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key." }, 26 | { names: ["isEmpty"], kind: CompletionItemKind.Method, documentation: "Returns true if this map contains no key-value mappings." }, 27 | { names: ["keySet"], kind: CompletionItemKind.Method, documentation: "Returns a Set view of the keys contained in this map." }, 28 | { names: ["merge"], kind: CompletionItemKind.Method, documentation: "If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value." }, 29 | { names: ["put"], kind: CompletionItemKind.Method, documentation: "Associates the specified value with the specified key in this map (optional operation)." }, 30 | { names: ["putAll"], kind: CompletionItemKind.Method, documentation: "Copies all of the mappings from the specified map to this map (optional operation)." }, 31 | { names: ["putIfAbsent"], kind: CompletionItemKind.Method, documentation: "If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value." }, 32 | { names: ["replace"], kind: CompletionItemKind.Method, documentation: "Replaces the entry for the specified key only if it is currently mapped to some value." }, 33 | { names: ["replaceAll"], kind: CompletionItemKind.Method, documentation: "Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception." }, 34 | { names: ["size"], kind: CompletionItemKind.Method, documentation: "Returns the number of key-value mappings in this map." }, 35 | { names: ["values"], kind: CompletionItemKind.Method, documentation: "Returns a Collection view of the values contained in this map." }, 36 | ] as Array; -------------------------------------------------------------------------------- /src/providers/util/dynamodb.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import { CompletionItemKind } from "vscode"; 3 | 4 | export default [{ 5 | prefixes: ['$util.dynamodb.'], 6 | properties: [ 7 | { names: ["toDynamoDB"], kind: CompletionItemKind.Method, documentation: "General object conversion tool for DynamoDB that converts input objects to the appropriate DynamoDB representation. It’s opinionated about how it represents some types: e.g., it will use lists (“L”) rather than sets (“SS”, “NS”, “BS”). This returns an object that describes the DynamoDB attribute value." }, 8 | 9 | { names: ["toDynamoDBJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toDynamoDB(Object) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 10 | 11 | { names: ["toString"], kind: CompletionItemKind.Method, documentation: "Convert an input string to the DynamoDB string format. This returns an object that describes the DynamoDB attribute value." }, 12 | 13 | { names: ["toStringJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toString(String) : String, but returns the DynamoDB attribute value as a JSON encoded string." }, 14 | 15 | { names: ["toStringSet"], kind: CompletionItemKind.Method, documentation: "Converts a lists with Strings to the DynamoDB string set format. This returns an object that describes the DynamoDB attribute value." }, 16 | 17 | { names: ["toStringSetJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toStringSet(List) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 18 | 19 | { names: ["toNumber"], kind: CompletionItemKind.Method, documentation: "Converts a number to the DynamoDB number format. This returns an object that describes the DynamoDB attribute value." }, 20 | 21 | { names: ["toNumberJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toNumber(Number) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 22 | 23 | { names: ["toNumberSet"], kind: CompletionItemKind.Method, documentation: "Converts a list of numbers to the DynamoDB number set format. This returns an object that describes the DynamoDB attribute value." }, 24 | 25 | { names: ["toNumberSetJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toNumberSet(List) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 26 | 27 | { names: ["toBinary"], kind: CompletionItemKind.Method, documentation: "Converts binary data encoded as a base64 string to DynamoDB binary format. This returns an object that describes the DynamoDB attribute value." }, 28 | 29 | { names: ["toBinaryJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toBinary(String) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 30 | 31 | { names: ["toBinarySet"], kind: CompletionItemKind.Method, documentation: "Converts a list of binary data encoded as base64 strings to DynamoDB binary set format. This returns an object that describes the DynamoDB attribute value." }, 32 | 33 | { names: ["toBinarySetJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toBinarySet(List) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 34 | 35 | { names: ["toBoolean"], kind: CompletionItemKind.Method, documentation: "Converts a boolean to the appropriate DynamoDB boolean format. This returns an object that describes the DynamoDB attribute value." }, 36 | 37 | { names: ["toBooleanJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toBoolean(boolean) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 38 | 39 | { names: ["toNull"], kind: CompletionItemKind.Method, documentation: "Returns a null in DynamoDB null format. This returns an object that describes the DynamoDB attribute value." }, 40 | 41 | { names: ["toNullJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toNull() : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 42 | 43 | { names: ["toList"], kind: CompletionItemKind.Method, documentation: "Converts a list of object to DynamoDB list format. Each item in the list is also converted to its appropriate DynamoDB format. It’s opinionated about how it represents some of the nested objects: e.g., it will use lists (“L”) rather than sets (“SS”, “NS”, “BS”). This returns an object that describes the DynamoDB attribute value." }, 44 | 45 | { names: ["toListJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toList(List) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 46 | 47 | { names: ["toMap"], kind: CompletionItemKind.Method, documentation: "Converts a map to DynamoDB map format. Each value in the map is also converted to its appropriate DynamoDB format. It’s opinionated about how it represents some of the nested objects: e.g., it will use lists (“L”) rather than sets (“SS”, “NS”, “BS”). This returns an object that describes the DynamoDB attribute value." }, 48 | 49 | { names: ["toMapJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toMap(Map) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 50 | 51 | { names: ["toMapValues"], kind: CompletionItemKind.Method, documentation: "Creates a copy of the map where each value has been converted to its appropriate DynamoDB format. It’s opinionated about how it represents some of the nested objects: e.g., it will use lists (“L”) rather than sets (“SS”, “NS”, “BS”)." }, 52 | 53 | { names: ["toMapValuesJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toMapValues(Map) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 54 | 55 | { names: ["toS3Object"], kind: CompletionItemKind.Method, documentation: "Converts the key, bucket and region into the DynamoDB S3 Object representation. This returns an object that describes the DynamoDB attribute value." }, 56 | 57 | { names: ["toS3ObjectJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toS3Object(String key, String bucket, String region) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 58 | 59 | { names: ["toS3Object"], kind: CompletionItemKind.Method, documentation: "Converts the key, bucket, region and optional version into the DynamoDB S3 Object representation. This returns an object that describes the DynamoDB attribute value." }, 60 | 61 | { names: ["toS3ObjectJson"], kind: CompletionItemKind.Method, documentation: "The same as $util.dynamodb.toS3Object(String key, String bucket, String region, String version) : Map, but returns the DynamoDB attribute value as a JSON encoded string." }, 62 | 63 | { names: ["fromS3ObjectJson"], kind: CompletionItemKind.Method, documentation: "Accepts the string value of a DynamoDB S3 Object and returns a map that contains the key, bucket, region and optional version." }, 64 | ] 65 | }] as Array; -------------------------------------------------------------------------------- /src/providers/util/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { AutocompleteData } from '../dataTypes'; 3 | import { CompletionItemKind, MarkdownString } from "vscode"; 4 | import time from "./time"; 5 | import list from "./list"; 6 | import map from "./map"; 7 | import dynamodb from "./dynamodb"; 8 | 9 | export default [{ 10 | prefixes: ['$util.'], 11 | properties: [ 12 | { names: ["qr", "quiet"], kind: CompletionItemKind.Method, documentation: "Executes a VTL statement while suppressing the returned value of the execution. This is useful if you wish to run methods without using temporary placeholders such as adding items to a map, etc." }, 13 | { names: ["escapeJavaScript"], kind: CompletionItemKind.Method, documentation: "Returns the input string as a JavasScript escaped string." }, 14 | { names: ["urlEncode"], kind: CompletionItemKind.Method, documentation: "Returns the input string as an `application/x-www-form-urlencoded` encoded string." }, 15 | { names: ["urlDecode"], kind: CompletionItemKind.Method, documentation: "Decodes an `application/x-www-form-urlencoded` encoded string back to its non-encoded form." }, 16 | { names: ["base64Encode"], kind: CompletionItemKind.Method, documentation: "Encodes the input into a base64-encoded string." }, 17 | { names: ["base64Decode"], kind: CompletionItemKind.Method, documentation: "Decodes the data from a base64-encoded string." }, 18 | { names: ["parseJson"], kind: CompletionItemKind.Method, documentation: 'Takes “stringified” JSON and returns an object representation of the result.' }, 19 | { names: ["toJson"], kind: CompletionItemKind.Method, documentation: 'Takes an object and returns a “stringified” JSON representation of that object.' }, 20 | { names: ["autoId"], kind: CompletionItemKind.Method, documentation: 'Returns a 128-bit randomly generated UUID.' }, 21 | { names: ["unauthorized"], kind: CompletionItemKind.Method, documentation: 'Throws Unauthorized for the field being resolved. This can be used in request or response mapping templates to decide if the caller should be allowed to resolve the field.' }, 22 | { 23 | names: ["error"], kind: CompletionItemKind.Method, documentation: 'Throws a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result.', 24 | signatures: [ 25 | { 26 | label: "error(String error)", 27 | documentation: "Throws a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result.", 28 | parameters: [ 29 | { 30 | label: "String error" 31 | } 32 | ] 33 | }, 34 | { 35 | label: "error(String error, String errorType)", 36 | documentation: new MarkdownString("Throws a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result. Additionally, an `errorType` can be specified."), 37 | parameters: [ 38 | { 39 | label: "String error" 40 | }, 41 | { 42 | label: "String errorType" 43 | } 44 | ] 45 | }, 46 | { 47 | label: "error(String error, String errorType, Object data)", 48 | documentation: new MarkdownString("Throws a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result. Additionally, an `errorType` and a `data` field can be specified. The `data` value will be added to the corresponding error block inside `errors` in the GraphQL response. **Note**: `data` will be filtered based on the query selection set."), 49 | parameters: [ 50 | { 51 | label: "String error" 52 | }, 53 | { 54 | label: "String errorType" 55 | }, 56 | { 57 | label: "Object data" 58 | } 59 | ] 60 | }, 61 | { 62 | label: "error(String error, String errorType, Object data, Object errorInfo)", 63 | documentation: new MarkdownString("Throws a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result. Additionally, an `errorType` field, a `data` field, and a `errorInfo` field can be specified. The data value will be added to the corresponding error block inside errors in the GraphQL response. **Note**: `data` will be filtered based on the query selection set. The `errorInfo` value will be added to the corresponding `error` block inside `errors` in the GraphQL response. **Note**: `errorInfo` will NOT be filtered based on the query selection set."), 64 | parameters: [ 65 | { 66 | label: "String error" 67 | }, 68 | { 69 | label: "String errorType" 70 | }, 71 | { 72 | label: "Object data" 73 | }, 74 | { 75 | label: "Object errorInfo" 76 | } 77 | ] 78 | } 79 | ] 80 | 81 | }, 82 | { names: ["appendError"], kind: CompletionItemKind.Method, documentation: 'Appends a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result. Unlike `$util.error(String)`, the template evaluation will not be interrupted, so that data can be returned to the caller.' }, 83 | { names: ["validate"], kind: CompletionItemKind.Method, documentation: 'If the condition is false, throw a CustomTemplateException with the specified message.' }, 84 | { names: ["isNull"], kind: CompletionItemKind.Method, documentation: 'Returns true if the supplied object is null.' }, 85 | { names: ["isNullOrEmpty"], kind: CompletionItemKind.Method, documentation: 'Returns true if the supplied data is null or an empty string. Otherwise, returns false.' }, 86 | { names: ["isNullOrBlank"], kind: CompletionItemKind.Method, documentation: 'Returns true if the supplied data is null or a blank string. Otherwise, returns false.' }, 87 | { names: ["defaultIfNull"], kind: CompletionItemKind.Method, documentation: 'Returns the first Object if it is not null. Otherwise, returns second object as a “default Object”.' }, 88 | { names: ["defaultIfNullOrEmpty"], kind: CompletionItemKind.Method, documentation: 'Returns the first String if it is not null or empty. Otherwise, returns second String as a “default String”.' }, 89 | { names: ["defaultIfNullOrBlank"], kind: CompletionItemKind.Method, documentation: 'Returns the first String if it is not null or blank. Otherwise, returns second String as a “default String”.' }, 90 | { names: ["isString"], kind: CompletionItemKind.Method, documentation: 'Returns true if Object is a String.' }, 91 | { names: ["isNumber"], kind: CompletionItemKind.Method, documentation: 'Returns true if Object is a Number.' }, 92 | { names: ["isBoolean"], kind: CompletionItemKind.Method, documentation: 'Returns true if Object is a Boolean.' }, 93 | { names: ["isList"], kind: CompletionItemKind.Method, documentation: 'Returns true if Object is a List.' }, 94 | { names: ["isMap"], kind: CompletionItemKind.Method, documentation: 'Returns true if Object is a Map.' }, 95 | { names: ["typeOf"], kind: CompletionItemKind.Method, documentation: 'Returns a String describing the type of the Object. Supported type identifications are: “Null”, “Number”, “String”, “Map”, “List”, “Boolean”. If a type cannot be identified, the return type is “Object”.' }, 96 | { names: ["matches"], kind: CompletionItemKind.Method, documentation: 'Returns true if the specified pattern in the first argument matches the supplied data in the second argument. The pattern must be a regular expression such as `$util.matches("a*b", "aaaaab")`. The functionality is based on [Pattern](https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html), which you can reference for further documentation.' }, 97 | 98 | { names: ["time"], documentation: 'The [`$util.time`](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#time-helpers-in-util-time) variable contains datetime methods to help generate timestamps, convert between datetime formats, and parse datetime strings. The syntax for datetime formats is based on [DateTimeFormatter](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html) which you can reference for further documentation.' }, 99 | 100 | { names: ["list"], documentation: "[`$util.list`](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#list-helpers-in-util-list) contains methods to help with common List operations, such as removing or retaining items from a list for filtering use cases." }, 101 | 102 | { names: ["map"], documentation: "[`$util.map`](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#map-helpers-in-util-map) contains methods to help with common Map operations, such as removing or retaining items from a Map for filtering use cases." }, 103 | 104 | { names: ["dynamodb"], documentation: "[`$util.dynamodb`](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#dynamodb-helpers-in-util-dynamodb) contains helper methods that make it easier to write and read data to Amazon DynamoDB, such as automatic type mapping and formatting. These methods are designed to make mapping primitive types and Lists to the proper DynamoDB input format automatically, which is a Map of the format `{ \"TYPE\" : VALUE }`." }, 105 | ] 106 | }, 107 | ...time, 108 | ...list, 109 | ...map, 110 | ...dynamodb 111 | ] as Array; -------------------------------------------------------------------------------- /src/providers/util/list.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import { CompletionItemKind } from "vscode"; 3 | 4 | export default [{ 5 | prefixes: ['$util.list.'], 6 | properties: [ 7 | { names: ["copyAndRetainAll"], kind: CompletionItemKind.Method, documentation: "Makes a shallow copy of the supplied list in the first argument, retaining only the items specified in the second argument, if they are present. All other items will be removed from the copy." }, 8 | 9 | { names: ["copyAndRemoveAll"], kind: CompletionItemKind.Method, documentation: "Makes a shallow copy of the supplied list in the first argument, removing any items where the item is specified in the second argument, if they are present. All other items will be retained in the copy." }, 10 | ] 11 | }] as Array; -------------------------------------------------------------------------------- /src/providers/util/map.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import { CompletionItemKind } from "vscode"; 3 | 4 | export default [{ 5 | prefixes: ['$util.map.'], 6 | properties: [ 7 | { names: ["copyAndRetainAllKeys"], kind: CompletionItemKind.Method, documentation: "Makes a shallow copy of the first map, retaining only the keys specified in the list, if they are present. All other keys will be removed from the copy." }, 8 | 9 | { names: ["copyAndRemoveAllKeys"], kind: CompletionItemKind.Method, documentation: "Makes a shallow copy of the first map, removing any entries where the key is specified in the list, if they are present. All other keys will be retained in the copy." }, 10 | ] 11 | }] as Array; -------------------------------------------------------------------------------- /src/providers/util/time.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteData } from "../dataTypes"; 2 | import { CompletionItemKind } from "vscode"; 3 | 4 | export default [{ 5 | prefixes: ['$util.time.'], 6 | properties: [ 7 | { names: ["nowISO8601"], kind: CompletionItemKind.Method, documentation: "Returns a String representation of UTC in [ISO8601 format](https://en.wikipedia.org/wiki/ISO_8601)." }, 8 | { names: ["nowEpochSeconds"], kind: CompletionItemKind.Method, documentation: "Returns the number of seconds from the epoch of 1970-01-01T00:00:00Z to now." }, 9 | { names: ["nowEpochMilliSeconds"], kind: CompletionItemKind.Method, documentation: "Returns the number of milliseconds from the epoch of 1970-01-01T00:00:00Z to now." }, 10 | 11 | { names: ["nowFormatted"], kind: CompletionItemKind.Method, documentation: "Returns a string of the current timestamp in UTC using the specified format from a String input type." }, 12 | 13 | { names: ["nowFormatted"], kind: CompletionItemKind.Method, documentation: "Returns a string of the current timestamp for a timezone using the specified format and timezone from String input types." }, 14 | 15 | { names: ["parseFormattedToEpochMilliSeconds"], kind: CompletionItemKind.Method, documentation: "Parses a timestamp passed as a String, along with a format, and return the timestamp as milliseconds since epoch." }, 16 | 17 | { names: ["parseFormattedToEpochMilliSeconds"], kind: CompletionItemKind.Method, documentation: "Parses a timestamp passed as a String, along with a format and time zone, and return the timestamp as milliseconds since epoch." }, 18 | 19 | { names: ["parseISO8601ToEpochMilliSeconds"], kind: CompletionItemKind.Method, documentation: "Parses an ISO8601 timestamp, passed as a String, and return the timestamp as milliseconds since epoch." }, 20 | 21 | { names: ["epochMilliSecondsToSeconds"], kind: CompletionItemKind.Method, documentation: "Converts an epoch milliseconds timestamp to an epoch seconds timestamp." }, 22 | 23 | { names: ["epochMilliSecondsToISO8601"], kind: CompletionItemKind.Method, documentation: "Converts a epoch milliseconds timestamp to an ISO8601 timestamp." }, 24 | 25 | { names: ["epochMilliSecondsToFormatted"], kind: CompletionItemKind.Method, documentation: "Converts a epoch milliseconds timestamp, passed as long, to a timestamp formatted according to the supplied format in UTC." }, 26 | 27 | { names: ["epochMilliSecondsToFormatted"], kind: CompletionItemKind.Method, documentation: "Converts a epoch milliseconds timestamp, passed as a long, to a timestamp formatted according to the supplied format in the supplied timezone." }, 28 | ] 29 | }] as Array; -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /test_templates/dynamo.vtl: -------------------------------------------------------------------------------- 1 | #set($range = [0..5]) 2 | 3 | $util.toJson({ 4 | "foo": "bar" 5 | }) 6 | 7 | { 8 | "test": true 9 | #foreach($i in $range) 10 | ,"idx_$i": "The $i index" 11 | #end 12 | 13 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | 25 | ## Explore the API 26 | 27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 28 | 29 | ## Run tests 30 | 31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 32 | * Press `F5` to run the tests in a new window with your extension loaded. 33 | * See the output of the test result in the debug console. 34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | --------------------------------------------------------------------------------