@@ -13,12 +13,23 @@ import { SystemUtilities } from '../systemUtilities'
13
13
import { getLogger } from '../logger'
14
14
import { lambdaPackageTypeImage } from '../constants'
15
15
import { isCloud9 } from '../extensionUtilities'
16
+ import { isUntitledScheme , normalizeVSCodeUri } from '../utilities/vsCodeUtils'
16
17
17
18
export namespace CloudFormation {
18
19
export const SERVERLESS_API_TYPE = 'AWS::Serverless::Api' // eslint-disable-line @typescript-eslint/naming-convention
19
20
export const SERVERLESS_FUNCTION_TYPE = 'AWS::Serverless::Function' // eslint-disable-line @typescript-eslint/naming-convention
20
21
export const LAMBDA_FUNCTION_TYPE = 'AWS::Lambda::Function' // eslint-disable-line @typescript-eslint/naming-convention
21
22
23
+ export const templateFileGlobPattern = '**/*.{yaml,yml}'
24
+ export const devfileExcludePattern = / .* d e v f i l e \. ( y a m l | y m l ) / i
25
+ /**
26
+ * Match any file path that contains a .aws-sam folder. The way this works is:
27
+ * match anything that starts with a '/' or '\', then '.aws-sam', then either
28
+ * a '/' or '\' followed by any number of characters or end of a string (so it
29
+ * matches both /.aws-sam or /.aws-sam/<any number of characters>)
30
+ */
31
+ export const templateFileExcludePattern = / .* [ / \\ ] \. a w s - s a m ( [ / \\ ] .* | $ ) /
32
+
22
33
export function isZipLambdaResource (
23
34
resource ?: ZipResourceProperties | ImageResourceProperties
24
35
) : resource is ZipResourceProperties {
@@ -364,6 +375,22 @@ export namespace CloudFormation {
364
375
[ key : string ] : Resource | undefined
365
376
}
366
377
378
+ /** Returns true if the given name or path is a valid CloudFormation or SAM filename. */
379
+ export function isValidFilename ( filename : string | vscode . Uri ) : boolean {
380
+ filename = typeof filename === 'string' ? filename : filename . fsPath
381
+ filename = filename . trim ( )
382
+ if ( ! filename . endsWith ( '.yml' ) && ! filename . endsWith ( '.yaml' ) ) {
383
+ return false
384
+ }
385
+ // Note: intentionally _not_ checking `templateFileExcludePattern` here, because while excluding
386
+ // template files in .aws-sam/ is relevant for the workspace scan, it's irrelevant if such
387
+ // a file was opened explicitly by the user.
388
+ if ( filename . match ( devfileExcludePattern ) ) {
389
+ return false
390
+ }
391
+ return true
392
+ }
393
+
367
394
export async function load ( filename : string , validate : boolean = true ) : Promise < Template > {
368
395
if ( ! ( await SystemUtilities . fileExists ( filename ) ) ) {
369
396
throw new Error ( `Template file not found: ${ filename } ` )
@@ -384,6 +411,51 @@ export namespace CloudFormation {
384
411
return template
385
412
}
386
413
414
+ /**
415
+ * Returns a `CloudFormation.Template` if the given file (on disk) or `contents` is a valid
416
+ * CloudFormation document, or `{ template: undefined, kind: undefined }` if the file is
417
+ * invalid.
418
+ */
419
+ export async function tryLoad (
420
+ uri : vscode . Uri ,
421
+ contents ?: string
422
+ ) : Promise < { template : CloudFormation . Template | undefined ; kind : 'sam' | 'cfn' | undefined } > {
423
+ const rv : {
424
+ template : CloudFormation . Template | undefined
425
+ kind : 'sam' | 'cfn' | undefined
426
+ } = { template : undefined , kind : undefined }
427
+ try {
428
+ if ( isUntitledScheme ( uri ) ) {
429
+ if ( ! contents ) {
430
+ // this error technically just throw us into the catch so the error message isn't used
431
+ throw new Error ( 'Contents must be defined for untitled uris' )
432
+ }
433
+ rv . template = await CloudFormation . loadByContents ( contents , false )
434
+ } else {
435
+ rv . template = await CloudFormation . load ( normalizeVSCodeUri ( uri ) , false )
436
+ }
437
+ } catch ( e ) {
438
+ return {
439
+ template : undefined ,
440
+ kind : undefined ,
441
+ }
442
+ }
443
+
444
+ // Check if the template is a SAM template, using the same heuristic as the cfn-lint team:
445
+ // https://github.com/aws-cloudformation/aws-cfn-lint-visual-studio-code/blob/629de0bac4f36cfc6534e409a6f6766a2240992f/client/src/yaml-support/yaml-schema.ts#L39-L51
446
+ if ( rv . template . AWSTemplateFormatVersion || rv . template . Resources ) {
447
+ rv . kind =
448
+ rv . template . Transform && rv . template . Transform . toString ( ) . startsWith ( 'AWS::Serverless' ) ? 'sam' : 'cfn'
449
+
450
+ return rv
451
+ }
452
+
453
+ return {
454
+ template : undefined ,
455
+ kind : undefined ,
456
+ }
457
+ }
458
+
387
459
export async function save ( template : Template , filename : string ) : Promise < void > {
388
460
const templateAsYaml : string = yaml . dump ( template )
389
461
0 commit comments