Skip to content

Commit 6cb3868

Browse files
authored
Add environment file parsing handler (#187)
* Add environment file parsing handler
1 parent 81ec0f7 commit 6cb3868

File tree

11 files changed

+490
-0
lines changed

11 files changed

+490
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { OnStackFailure } from '@aws-sdk/client-cloudformation';
2+
import { z } from 'zod';
3+
import { DocumentType } from '../document/Document';
4+
import { ParseEnvironmentFilesParams, DeploymentConfig } from './EnvironmentRequestType';
5+
6+
const DocumentInfoSchema = z.object({
7+
type: z.enum(DocumentType),
8+
content: z.string(),
9+
fileName: z.string(),
10+
});
11+
12+
const ParseEnvironmentFilesParamsSchema = z.object({
13+
documents: z.array(DocumentInfoSchema),
14+
});
15+
16+
const DeploymentConfigSchema = z
17+
.object({
18+
'template-file-path': z.string().optional(),
19+
parameters: z.record(z.string(), z.string()).optional(),
20+
tags: z.record(z.string(), z.string()).optional(),
21+
'on-stack-failure': z.enum(OnStackFailure).optional(),
22+
'include-nested-stacks': z.boolean().optional(),
23+
'import-existing-resources': z.boolean().optional(),
24+
})
25+
.refine((data) => Object.values(data).some((value) => value !== undefined), {
26+
message: 'At least one property must be provided',
27+
});
28+
29+
export function parseEnvironmentFileParams(input: unknown): ParseEnvironmentFilesParams {
30+
return ParseEnvironmentFilesParamsSchema.parse(input);
31+
}
32+
33+
export function parseDeploymentConfig(input: unknown): DeploymentConfig {
34+
const parsed = DeploymentConfigSchema.parse(input);
35+
36+
return {
37+
templateFilePath: parsed['template-file-path'],
38+
parameters: parsed['parameters'],
39+
tags: parsed['tags'],
40+
onStackFailure: parsed['on-stack-failure'],
41+
includeNestedStacks: parsed['include-nested-stacks'],
42+
importExistingResources: parsed['import-existing-resources'],
43+
};
44+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { OnStackFailure } from '@aws-sdk/client-cloudformation';
2+
import { RequestType } from 'vscode-languageserver';
3+
import { DocumentType } from '../document/Document';
4+
5+
export type DocumentInfo = {
6+
type: DocumentType;
7+
content: string;
8+
fileName: string;
9+
};
10+
11+
export type DeploymentConfig = {
12+
templateFilePath?: string;
13+
parameters?: Record<string, string>;
14+
tags?: Record<string, string>;
15+
includeNestedStacks?: boolean;
16+
importExistingResources?: boolean;
17+
onStackFailure?: OnStackFailure;
18+
};
19+
20+
export type ParsedEnvironmentFile = {
21+
deploymentConfig: DeploymentConfig;
22+
fileName: string;
23+
};
24+
25+
export type ParseEnvironmentFilesParams = {
26+
documents: DocumentInfo[];
27+
};
28+
29+
export type ParseEnvironmentFilesResult = {
30+
parsedFiles: ParsedEnvironmentFile[];
31+
};
32+
33+
export const ParseEnvironmentFilesRequest = new RequestType<
34+
ParseEnvironmentFilesParams,
35+
ParseEnvironmentFilesResult,
36+
void
37+
>('aws/cfn/environment/files/parse');

src/handlers/EnvironmentHandler.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { load } from 'js-yaml';
2+
import { RequestHandler } from 'vscode-languageserver';
3+
import { DocumentType } from '../document/Document';
4+
import { parseDeploymentConfig, parseEnvironmentFileParams } from '../environments/EnvironmentParser';
5+
import {
6+
ParsedEnvironmentFile,
7+
ParseEnvironmentFilesParams,
8+
ParseEnvironmentFilesResult,
9+
} from '../environments/EnvironmentRequestType';
10+
import { TelemetryService } from '../telemetry/TelemetryService';
11+
import { handleLspError } from '../utils/Errors';
12+
import { parseWithPrettyError } from '../utils/ZodErrorWrapper';
13+
14+
export function parseEnvironmentFilesHandler(): RequestHandler<
15+
ParseEnvironmentFilesParams,
16+
ParseEnvironmentFilesResult,
17+
void
18+
> {
19+
const telemetry = TelemetryService.instance.get('EnvironmentHandler');
20+
21+
return (rawParams): ParseEnvironmentFilesResult => {
22+
return telemetry.measure('parseEnvironmentFiles', () => {
23+
try {
24+
const parsedFiles: ParsedEnvironmentFile[] = [];
25+
26+
const params = parseWithPrettyError(parseEnvironmentFileParams, rawParams);
27+
28+
for (const document of params.documents) {
29+
try {
30+
let parsedContent: unknown;
31+
if (document.type === DocumentType.JSON) {
32+
parsedContent = JSON.parse(document.content);
33+
} else if (document.type === DocumentType.YAML) {
34+
parsedContent = load(document.content);
35+
} else {
36+
continue;
37+
}
38+
39+
const deploymentConfig = parseWithPrettyError(parseDeploymentConfig, parsedContent);
40+
41+
parsedFiles.push({
42+
fileName: document.fileName,
43+
deploymentConfig: deploymentConfig,
44+
});
45+
} catch {
46+
telemetry.count('environmentFile.malformed', 1);
47+
}
48+
}
49+
50+
return {
51+
parsedFiles: parsedFiles,
52+
};
53+
} catch (error) {
54+
handleLspError(error, 'Failed to parse environment files');
55+
}
56+
});
57+
};
58+
}

src/protocol/LspComponents.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { LspAuthHandlers } from './LspAuthHandlers';
22
import { LspCommunication } from './LspCommunication';
33
import { LspDiagnostics } from './LspDiagnostics';
44
import { LspDocuments } from './LspDocuments';
5+
import { LspEnvironmentHandlers } from './LspEnvironmentHandlers';
56
import { LspHandlers } from './LspHandlers';
67
import { LspRelatedResourcesHandlers } from './LspRelatedResourcesHandlers';
78
import { LspResourceHandlers } from './LspResourceHandlers';
@@ -18,6 +19,7 @@ export class LspComponents {
1819
public readonly handlers: LspHandlers,
1920
public readonly authHandlers: LspAuthHandlers,
2021
public readonly stackHandlers: LspStackHandlers,
22+
public readonly environmentHandlers: LspEnvironmentHandlers,
2123
public readonly resourceHandlers: LspResourceHandlers,
2224
public readonly relatedResourcesHandlers: LspRelatedResourcesHandlers,
2325
public readonly s3Handlers: LspS3Handlers,

src/protocol/LspConnection.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { LspCommunication } from './LspCommunication';
1313
import { LspComponents } from './LspComponents';
1414
import { LspDiagnostics } from './LspDiagnostics';
1515
import { LspDocuments } from './LspDocuments';
16+
import { LspEnvironmentHandlers } from './LspEnvironmentHandlers';
1617
import { LspHandlers } from './LspHandlers';
1718
import { LspRelatedResourcesHandlers } from './LspRelatedResourcesHandlers';
1819
import { LspResourceHandlers } from './LspResourceHandlers';
@@ -35,6 +36,7 @@ export class LspConnection {
3536
private readonly handlers: LspHandlers;
3637
private readonly authHandlers: LspAuthHandlers;
3738
private readonly stackHandlers: LspStackHandlers;
39+
private readonly environmentHandlers: LspEnvironmentHandlers;
3840
private readonly resourceHandlers: LspResourceHandlers;
3941
private readonly relatedResourcesHandlers: LspRelatedResourcesHandlers;
4042
private readonly s3Handlers: LspS3Handlers;
@@ -59,6 +61,7 @@ export class LspConnection {
5961
this.handlers = new LspHandlers(this.connection);
6062
this.authHandlers = new LspAuthHandlers(this.connection);
6163
this.stackHandlers = new LspStackHandlers(this.connection);
64+
this.environmentHandlers = new LspEnvironmentHandlers(this.connection);
6265
this.resourceHandlers = new LspResourceHandlers(this.connection);
6366
this.relatedResourcesHandlers = new LspRelatedResourcesHandlers(this.connection);
6467
this.s3Handlers = new LspS3Handlers(this.connection);
@@ -93,6 +96,7 @@ export class LspConnection {
9396
this.handlers,
9497
this.authHandlers,
9598
this.stackHandlers,
99+
this.environmentHandlers,
96100
this.resourceHandlers,
97101
this.relatedResourcesHandlers,
98102
this.s3Handlers,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Connection, RequestHandler } from 'vscode-languageserver';
2+
import {
3+
ParseEnvironmentFilesParams,
4+
ParseEnvironmentFilesResult,
5+
ParseEnvironmentFilesRequest,
6+
} from '../environments/EnvironmentRequestType';
7+
8+
export class LspEnvironmentHandlers {
9+
constructor(private readonly connection: Connection) {}
10+
11+
onParseEnvironmentFiles(handler: RequestHandler<ParseEnvironmentFilesParams, ParseEnvironmentFilesResult, void>) {
12+
this.connection.onRequest(ParseEnvironmentFilesRequest.method, handler);
13+
}
14+
}

src/server/CfnServer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { configurationHandler } from '../handlers/ConfigurationHandler';
77
import { definitionHandler } from '../handlers/DefinitionHandler';
88
import { didChangeHandler, didCloseHandler, didOpenHandler, didSaveHandler } from '../handlers/DocumentHandler';
99
import { documentSymbolHandler } from '../handlers/DocumentSymbolHandler';
10+
import { parseEnvironmentFilesHandler } from '../handlers/EnvironmentHandler';
1011
import { executionHandler } from '../handlers/ExecutionHandler';
1112
import { hoverHandler } from '../handlers/HoverHandler';
1213
import { initializedHandler } from '../handlers/Initialize';
@@ -126,6 +127,8 @@ export class CfnServer {
126127
this.lsp.stackHandlers.onClearStackEvents(clearStackEventsHandler(this.components));
127128
this.lsp.stackHandlers.onGetStackOutputs(getStackOutputsHandler(this.components));
128129

130+
this.lsp.environmentHandlers.onParseEnvironmentFiles(parseEnvironmentFilesHandler());
131+
129132
this.lsp.relatedResourcesHandlers.onGetAuthoredResourceTypes(getAuthoredResourceTypesHandler(this.components));
130133
this.lsp.relatedResourcesHandlers.onGetRelatedResourceTypes(getRelatedResourceTypesHandler(this.components));
131134
this.lsp.relatedResourcesHandlers.onInsertRelatedResources(insertRelatedResourcesHandler(this.components));

tools/telemetry-generator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import { LspS3Handlers } from '../src/protocol/LspS3Handlers';
6969
import { ExtendedInitializeParams } from '../src/server/InitParams';
7070
import { FeatureFlagProvider } from '../src/featureFlag/FeatureFlagProvider';
7171
import { RelationshipSchemaService } from '../src/services/RelationshipSchemaService';
72+
import { LspEnvironmentHandlers } from '../src/protocol/LspEnvironmentHandlers';
7273

7374
const argv = yargs(hideBin(process.argv))
7475
.option('templates', {
@@ -184,6 +185,7 @@ function main() {
184185
stubInterface<LspHandlers>(),
185186
createMockAuthHandlers(),
186187
stubInterface<LspStackHandlers>(),
188+
stubInterface<LspEnvironmentHandlers>(),
187189
stubInterface<LspResourceHandlers>(),
188190
stubInterface<LspRelatedResourcesHandlers>(),
189191
stubInterface<LspS3Handlers>(),

0 commit comments

Comments
 (0)