Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(server) - Add support for Ref in hover and autocomplete #248

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 139 additions & 66 deletions client/src/test/suite/completion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,81 @@ import * as vscode from "vscode";
import assert = require("assert");
import { getDocUri, activate } from "./helper";

suite("Should code complete", () => {
const docUri = getDocUri("completion", "completion.yaml");
const intrinsics = [
{
label: "!And",
kind: 11,
},
{
label: "!Base64",
kind: 11,
},
{
label: "!Cidr",
kind: 11,
},
{
label: "!Equals",
kind: 11,
},
{
label: "!FindInMap",
kind: 11,
},
{
label: "!GetAtt",
kind: 11,
},
{
label: "!GetAZs",
kind: 11,
},
{
label: "!If",
kind: 11,
},
{
label: "!ImportValue",
kind: 11,
},
{
label: "!Join",
kind: 11,
},
{
label: "!Not",
kind: 11,
},
{
label: "!Or",
kind: 11,
},
{
label: "!Ref",
kind: 11,
},
{
label: "!Select",
kind: 11,
},
{
label: "!Split",
kind: 11,
},
{
label: "!Sub",
kind: 11,
},
];

suite("Should code complete", () => {
test("Complete on empty template", async () => {
const docUri = getDocUri("completion", "completion.yaml");
await activate(docUri);

await testCompletion(docUri, new vscode.Position(0, 0), {
items: [
{
label: "!And",
kind: 11,
},
{
label: "!Base64",
kind: 11,
},
{
label: "!Cidr",
kind: 11,
},
{
label: "!Equals",
kind: 11,
},
{
label: "!FindInMap",
kind: 11,
},
{
label: "!GetAtt",
kind: 11,
},
{
label: "!GetAZs",
kind: 11,
},
{
label: "!If",
kind: 11,
},
{
label: "!ImportValue",
kind: 11,
},
{
label: "!Join",
kind: 11,
},
{
label: "!Not",
kind: 11,
},
{
label: "!Or",
kind: 11,
},
{
label: "!Ref",
kind: 11,
},
{
label: "!Select",
kind: 11,
},
{
label: "!Split",
kind: 11,
},
{
label: "!Sub",
kind: 11,
},
...intrinsics,
{
label: "object",
kind: 6,
Expand Down Expand Up @@ -125,6 +128,76 @@ suite("Should code complete", () => {
],
});
});

test("Complete on ref", async () => {
const docUri = getDocUri("completion", "completion2.yaml");
await activate(docUri);

const completion_intrinsics = intrinsics.filter(
(intrinsic) => intrinsic.label !== "!Ref"
);

await testCompletion(docUri, new vscode.Position(17, 19), {
items: [
...completion_intrinsics,
{
label: "Subnet1",
kind: 11,
},
{
label: "Subnet2",
kind: 11,
},
{
label: "RouteTable1",
kind: 11,
},
{
label: "Subnet1RouteTable1",
kind: 11,
},
{
label: "Vpc",
kind: 11,
},
],
});
});

test("Complete with full ref", async () => {
const docUri = getDocUri("completion", "completion2.yaml");
await activate(docUri);

const completion_intrinsics = intrinsics.filter(
(intrinsic) => intrinsic.label !== "!Ref"
);

await testCompletion(docUri, new vscode.Position(21, 22), {
items: [
...completion_intrinsics,
{
label: "!Ref Subnet1",
kind: 11,
},
{
label: "!Ref Subnet2",
kind: 11,
},
{
label: "!Ref RouteTable1",
kind: 11,
},
{
label: "!Ref Subnet1RouteTable1",
kind: 11,
},
{
label: "!Ref Vpc",
kind: 11,
},
],
});
});
});

export async function testCompletion(
Expand Down
23 changes: 23 additions & 0 deletions client/src/test/suite/fixtures/completion/completion2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

Parameters:
Vpc:
Type: AWS::EC2::VPC::Id
Resources:
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
Subnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: V
RouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref V
Subnet1RouteTable1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !R
SubnetId: !Ref Subnet1
24 changes: 24 additions & 0 deletions client/src/test/suite/fixtures/hover/hover.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

Parameters:
Vpc:
Type: AWS::EC2::VPC::Id
Resources:
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
Subnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: Vpc
RouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Subnet1RouteTable1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable1
SubnetId:
Ref: Subnet1
63 changes: 63 additions & 0 deletions client/src/test/suite/hover.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as vscode from "vscode";
import assert = require("assert");
import { getDocUri, activate } from "./helper";

suite("Should hover", () => {
test("Hover on !Ref to parameter", async () => {
const docUri = getDocUri("hover", "hover.yaml");
await activate(docUri);

await testHover(
docUri,
new vscode.Position(17, 20),
"\n```\n(Parameter) Vpc: AWS::EC2::VPC::Id\n```\n"
);
});
test("Hover on !Ref to resource", async () => {
const docUri = getDocUri("hover", "hover.yaml");
await activate(docUri);

await testHover(
docUri,
new vscode.Position(21, 31),
"\n```\n(Resource) RouteTable1: AWS::EC2::RouteTable\n```\n"
);
});
test("Hover on Ref: to resource", async () => {
const docUri = getDocUri("hover", "hover.yaml");
await activate(docUri);

await testHover(
docUri,
new vscode.Position(23, 17),
"\n```\n(Resource) Subnet1: AWS::EC2::Subnet\n```\n"
);
});
test("Hover on Ref: to parameter", async () => {
const docUri = getDocUri("hover", "hover.yaml");
await activate(docUri);

await testHover(
docUri,
new vscode.Position(13, 15),
"\n```\n(Parameter) Vpc: AWS::EC2::VPC::Id\n```\n"
);
});
});

export async function testHover(
docUri: vscode.Uri,
position: vscode.Position,
expectedHover: string
): Promise<void> {
// Executing the command `vscode.executeHoverProvider` to simulate triggering hover
const actualHovers = (await vscode.commands.executeCommand(
"vscode.executeHoverProvider",
docUri,
position
)) as vscode.Hover[];

const actualHover = actualHovers[0];
const gotMessage = (<vscode.MarkdownString>actualHover.contents[0]).value;
assert.equal(expectedHover, gotMessage);
}
27 changes: 10 additions & 17 deletions server/src/cfnSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,32 +57,25 @@ export class SettingsState extends YamlSettingsState {
constructor() {
super();
this.customTags = [
"!And",
"!And sequence",
"!If",
"!If sequence",
"!Not",
"!Not sequence",
"!Equals",
"!Equals sequence",
"!Or",
"!Or sequence",
"!FindInMap",
"!FindInMap sequence",
"!Base64",
"!Join",
"!Base64 scalar",
"!Join sequence",
"!Cidr",
"!Ref",
"!Sub",
"!Cidr sequence",
"!Ref scalar",
"!Sub scalar",
"!Sub sequence",
"!GetAtt",
"!GetAZs",
"!ImportValue",
"!ImportValue sequence",
"!Select",
"!GetAtt scalar",
"!GetAtt sequence",
"!GetAZs mapping",
"!GetAZs scalar",
"!ImportValue mapping",
"!ImportValue scalar",
"!Select sequence",
"!Split",
"!Split sequence",
];
this.schemaStoreEnabled = false;
Expand Down
Loading