diff --git a/src/shared/awsFiletypes.ts b/src/shared/awsFiletypes.ts index b1eb6b5aa74..ddd0e1a13fa 100644 --- a/src/shared/awsFiletypes.ts +++ b/src/shared/awsFiletypes.ts @@ -7,13 +7,13 @@ import * as vscode from 'vscode' import * as path from 'path' import * as constants from '../shared/constants' import * as aslFormats from '../stepFunctions/constants/aslFormats' -import * as pathutil from '../shared/utilities/pathUtils' import * as fsutil from '../shared/filesystemUtilities' import * as sysutil from '../shared/systemUtilities' import * as collectionUtil from '../shared/utilities/collectionUtils' import globals from './extensionGlobals' import { telemetry } from './telemetry/telemetry' import { AwsFiletype } from './telemetry/telemetry' +import { CloudFormation } from './cloudformation/cloudformation' /** AWS filetypes: vscode language ids */ export const awsFiletypeLangIds = { @@ -67,9 +67,12 @@ export function activate(): void { vscode.workspace.onDidOpenTextDocument(async (doc: vscode.TextDocument) => { const isAwsFileExt = isAwsFiletype(doc) const isSchemaHandled = globals.schemaService.isMapped(doc.uri) - const isCfnTemplate = !!(await globals.templateRegistry).items.find( - t => pathutil.normalize(t.path) === pathutil.normalize(doc.fileName) - ) + const cfnTemplate = + CloudFormation.isValidFilename(doc.uri) || doc.languageId === 'yaml' + ? await CloudFormation.tryLoad(doc.uri) + : undefined + const isCfnTemplate = cfnTemplate?.template !== undefined + if (!isAwsFileExt && !isSchemaHandled && !isCfnTemplate) { return } @@ -78,11 +81,12 @@ export function activate(): void { let fileExt: string | undefined = path.extname(doc.fileName) fileExt = fileExt ? fileExt : undefined // Telemetry client will fail on empty string. - // TODO: ask templateRegistry if this is SAM or CFN. // TODO: ask schemaService for the precise filetype. let telemKind = isAwsConfig(doc.fileName) ? 'awsCredentials' : langidToAwsFiletype(doc.languageId) - if (telemKind === 'other') { - telemKind = isCfnTemplate ? 'cloudformationSam' : isSchemaHandled ? 'cloudformation' : 'other' + if (isCfnTemplate) { + telemKind = cfnTemplate.kind === 'sam' ? 'cloudformationSam' : 'cloudformation' + } else if (telemKind === 'other') { + telemKind = isSchemaHandled ? 'cloudformation' : 'other' } // HACK: for "~/.aws/foo" vscode sometimes _only_ emits "~/.aws/foo.git". diff --git a/src/shared/cloudformation/activation.ts b/src/shared/cloudformation/activation.ts index d2a2e39fcd3..9326999e82f 100644 --- a/src/shared/cloudformation/activation.ts +++ b/src/shared/cloudformation/activation.ts @@ -10,23 +10,11 @@ import { isToolkitActive, localize } from '../utilities/vsCodeUtils' import { AsyncCloudFormationTemplateRegistry, CloudFormationTemplateRegistry } from '../fs/templateRegistry' import { getIdeProperties } from '../extensionUtilities' import { NoopWatcher } from '../fs/watchedFiles' -import { createStarterTemplateFile } from './cloudformation' +import { CloudFormation, createStarterTemplateFile } from './cloudformation' import { Commands } from '../vscode/commands2' import globals from '../extensionGlobals' import { SamCliSettings } from '../sam/cli/samCliSettings' -export const templateFileGlobPattern = '**/*.{yaml,yml}' - -/** - * Match any file path that contains a .aws-sam folder. The way this works is: - * match anything that starts with a '/' or '\', then '.aws-sam', then either - * a '/' or '\' followed by any number of characters or end of a string (so it - * matches both /.aws-sam or /.aws-sam/) - */ -export const templateFileExcludePattern = /.*[/\\]\.aws-sam([/\\].*|$)/ - -export const devfileExcludePattern = /.*devfile\.(yaml|yml)/i - /** * Creates a CloudFormationTemplateRegistry which retains the state of CloudFormation templates in a workspace. * This also assigns a FileSystemWatcher which will update the registry on any change to tracked templates. @@ -68,9 +56,9 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi */ function setTemplateRegistryInGlobals(registry: CloudFormationTemplateRegistry) { const registrySetupFunc = async (registry: CloudFormationTemplateRegistry) => { - await registry.addExcludedPattern(devfileExcludePattern) - await registry.addExcludedPattern(templateFileExcludePattern) - await registry.addWatchPatterns([templateFileGlobPattern]) + await registry.addExcludedPattern(CloudFormation.devfileExcludePattern) + await registry.addExcludedPattern(CloudFormation.templateFileExcludePattern) + await registry.addWatchPatterns([CloudFormation.templateFileGlobPattern]) await registry.watchUntitledFiles() return registry diff --git a/src/shared/cloudformation/cloudformation.ts b/src/shared/cloudformation/cloudformation.ts index 69f1f2fb347..78a4608106e 100644 --- a/src/shared/cloudformation/cloudformation.ts +++ b/src/shared/cloudformation/cloudformation.ts @@ -13,12 +13,23 @@ import { SystemUtilities } from '../systemUtilities' import { getLogger } from '../logger' import { lambdaPackageTypeImage } from '../constants' import { isCloud9 } from '../extensionUtilities' +import { isUntitledScheme, normalizeVSCodeUri } from '../utilities/vsCodeUtils' export namespace CloudFormation { export const SERVERLESS_API_TYPE = 'AWS::Serverless::Api' // eslint-disable-line @typescript-eslint/naming-convention export const SERVERLESS_FUNCTION_TYPE = 'AWS::Serverless::Function' // eslint-disable-line @typescript-eslint/naming-convention export const LAMBDA_FUNCTION_TYPE = 'AWS::Lambda::Function' // eslint-disable-line @typescript-eslint/naming-convention + export const templateFileGlobPattern = '**/*.{yaml,yml}' + export const devfileExcludePattern = /.*devfile\.(yaml|yml)/i + /** + * Match any file path that contains a .aws-sam folder. The way this works is: + * match anything that starts with a '/' or '\', then '.aws-sam', then either + * a '/' or '\' followed by any number of characters or end of a string (so it + * matches both /.aws-sam or /.aws-sam/) + */ + export const templateFileExcludePattern = /.*[/\\]\.aws-sam([/\\].*|$)/ + export function isZipLambdaResource( resource?: ZipResourceProperties | ImageResourceProperties ): resource is ZipResourceProperties { @@ -364,6 +375,22 @@ export namespace CloudFormation { [key: string]: Resource | undefined } + /** Returns true if the given name or path is a valid CloudFormation or SAM filename. */ + export function isValidFilename(filename: string | vscode.Uri): boolean { + filename = typeof filename === 'string' ? filename : filename.fsPath + filename = filename.trim() + if (!filename.endsWith('.yml') && !filename.endsWith('.yaml')) { + return false + } + // Note: intentionally _not_ checking `templateFileExcludePattern` here, because while excluding + // template files in .aws-sam/ is relevant for the workspace scan, it's irrelevant if such + // a file was opened explicitly by the user. + if (filename.match(devfileExcludePattern)) { + return false + } + return true + } + export async function load(filename: string, validate: boolean = true): Promise