11import { TextDocument , Position , Range , DocumentUri } from 'vscode-languageserver-textdocument' ;
2+ import { TopLevelSection } from '../context/ContextType' ;
23import { DefaultSettings } from '../settings/Settings' ;
34import { LoggerFactory } from '../telemetry/LoggerFactory' ;
4- import { detectCfnFileType } from './CloudFormationDetection' ;
55import { DocumentMetadata } from './DocumentProtocol' ;
66import { detectDocumentType , uriToPath } from './DocumentUtils' ;
77import { parseValidYaml } from './YamlParser' ;
@@ -10,9 +10,10 @@ export class Document {
1010 private readonly log = LoggerFactory . getLogger ( Document ) ;
1111 public readonly extension : string ;
1212 public readonly documentType : DocumentType ;
13- public readonly cfnFileType : CloudFormationFileType ;
13+ private _cfnFileType : CloudFormationFileType ;
1414 public readonly fileName : string ;
1515 private tabSize : number ;
16+ private cachedParsedContent : unknown ;
1617
1718 constructor (
1819 private readonly textDocument : TextDocument ,
@@ -28,22 +29,87 @@ export class Document {
2829 this . extension = extension ;
2930 this . documentType = type ;
3031 this . fileName = uriToPath ( uri ) . base ;
32+ this . _cfnFileType = CloudFormationFileType . Unknown ;
3133
32- try {
33- this . cfnFileType = detectCfnFileType ( this . textDocument . getText ( ) , this . documentType ) ;
34- } catch ( error ) {
35- this . cfnFileType = CloudFormationFileType . Unknown ;
36- this . log . error ( error , `Failed to detect CloudFormation file type ${ this . textDocument . uri } ` ) ;
37- }
34+ this . updateCfnFileType ( ) ;
3835 this . tabSize = fallbackTabSize ;
3936 this . processIndentation ( detectIndentation , fallbackTabSize ) ;
4037 }
4138
42- public getParsedDocumentContent ( ) : unknown {
39+ public get cfnFileType ( ) : CloudFormationFileType {
40+ return this . _cfnFileType ;
41+ }
42+
43+ public updateCfnFileType ( ) : void {
44+ const content = this . textDocument . getText ( ) ;
45+ if ( ! content . trim ( ) ) {
46+ this . _cfnFileType = CloudFormationFileType . Unknown ;
47+ this . cachedParsedContent = undefined ;
48+ return ;
49+ }
50+
51+ try {
52+ this . cachedParsedContent = this . parseContent ( ) ;
53+ this . _cfnFileType = this . detectCfnFileType ( ) ;
54+ } catch {
55+ // If parsing fails, leave cfnFileType unchanged and clear cache
56+ this . cachedParsedContent = undefined ;
57+ this . log . debug (
58+ `Failed to parse document ${ this . textDocument . uri } , keeping cfnFileType as ${ this . _cfnFileType } ` ,
59+ ) ;
60+ }
61+ }
62+
63+ private parseContent ( ) : unknown {
64+ const content = this . textDocument . getText ( ) ;
4365 if ( this . documentType === DocumentType . JSON ) {
44- return JSON . parse ( this . contents ( ) ) ;
66+ return JSON . parse ( content ) ;
67+ }
68+ return parseValidYaml ( content ) ;
69+ }
70+
71+ private detectCfnFileType ( ) : CloudFormationFileType {
72+ // If languageId is cloudformation, treat as template
73+ if ( this . languageId === 'cloudformation' ) {
74+ return CloudFormationFileType . Template ;
75+ }
76+
77+ if ( ! this . cachedParsedContent || typeof this . cachedParsedContent !== 'object' ) {
78+ return CloudFormationFileType . Unknown ;
79+ }
80+
81+ const parsed = this . cachedParsedContent as Record < string , unknown > ;
82+
83+ // Check for GitSync deployment file
84+ const gitSyncKeys = [ 'template-file-path' , 'templateFilePath' , 'templatePath' ] ;
85+ if ( gitSyncKeys . some ( ( key ) => Object . prototype . hasOwnProperty . call ( parsed , key ) ) ) {
86+ return CloudFormationFileType . GitSyncDeployment ;
87+ }
88+
89+ // Check for CloudFormation template
90+ const templateKeys = [
91+ TopLevelSection . AWSTemplateFormatVersion ,
92+ TopLevelSection . Resources ,
93+ TopLevelSection . Transform ,
94+ ] ;
95+ if ( templateKeys . some ( ( key ) => Object . prototype . hasOwnProperty . call ( parsed , key ) ) ) {
96+ return CloudFormationFileType . Template ;
97+ }
98+
99+ return CloudFormationFileType . Unknown ;
100+ }
101+
102+ public getParsedDocumentContent ( ) : unknown {
103+ if ( this . cachedParsedContent !== undefined ) {
104+ return this . cachedParsedContent ;
105+ }
106+
107+ // Fallback to parsing if cache is empty
108+ try {
109+ return this . parseContent ( ) ;
110+ } catch {
111+ return undefined ;
45112 }
46- return parseValidYaml ( this . contents ( ) ) ;
47113 }
48114
49115 public getLine ( lineNumber : number ) : string | undefined {
0 commit comments