@@ -21,21 +21,20 @@ interface ProjectArgs {
2121
2222interface Project {
2323 config : CMKConfig ;
24- // TODO: Implement these methods later for watch mode
25- // /** Whether the file matches the wildcard patterns in `include` / `exclude` options */
26- // isWildcardMatchedFile(fileName: string): boolean;
27- // /**
28- // * Add a file to the project.
29- // * @throws {ReadCSSModuleFileError }
30- // */
31- // addFile(fileName: string): void;
32- // /**
33- // * Update a file in the project.
34- // * @throws {ReadCSSModuleFileError }
35- // */
36- // updateFile(fileName: string): void;
37- // /** Remove a file from the project. */
38- // removeFile(fileName: string): void;
24+ /** Whether the file matches the wildcard patterns in `include` / `exclude` options */
25+ isWildcardMatchedFile ( fileName : string ) : boolean ;
26+ /**
27+ * Add a file to the project.
28+ * @throws {ReadCSSModuleFileError }
29+ */
30+ addFile ( fileName : string ) : void ;
31+ /**
32+ * Update a file in the project.
33+ * @throws {ReadCSSModuleFileError }
34+ */
35+ updateFile ( fileName : string ) : void ;
36+ /** Remove a file from the project. */
37+ removeFile ( fileName : string ) : void ;
3938 /**
4039 * Get all diagnostics.
4140 * Including three types of diagnostics: project diagnostics, syntactic diagnostics, and semantic diagnostics.
@@ -72,16 +71,64 @@ export function createProject(args: ProjectArgs): Project {
7271 const resolver = createResolver ( config . compilerOptions , moduleResolutionCache ) ;
7372 const matchesPattern = createMatchesPattern ( config ) ;
7473
75- const parseStageCache = new Map < string , CSSModule > ( ) ;
76- const checkStageCache = new Map < string , Diagnostic [ ] > ( ) ;
77- const getCSSModule = ( path : string ) => parseStageCache . get ( path ) ;
74+ const cssModuleMap = new Map < string , CSSModule > ( ) ;
75+ const semanticDiagnosticsMap = new Map < string , Diagnostic [ ] > ( ) ;
76+ // Tracks whether .d.ts has been emitted after the last change
77+ const emittedSet = new Set < string > ( ) ;
78+ const getCSSModule = ( path : string ) => cssModuleMap . get ( path ) ;
7879 const exportBuilder = createExportBuilder ( { getCSSModule, matchesPattern, resolver } ) ;
7980
8081 for ( const fileName of getFileNamesByPattern ( config ) ) {
8182 // NOTE: Files may be deleted between executing `getFileNamesByPattern` and `tryParseCSSModule`.
8283 // Therefore, `tryParseCSSModule` may return `undefined`.
8384 const cssModule = tryParseCSSModule ( fileName ) ;
84- if ( cssModule ) parseStageCache . set ( fileName , cssModule ) ;
85+ if ( cssModule ) cssModuleMap . set ( fileName , cssModule ) ;
86+ }
87+
88+ /**
89+ * @throws {ReadCSSModuleFileError }
90+ */
91+ function addFile ( fileName : string ) {
92+ if ( cssModuleMap . has ( fileName ) ) return ;
93+
94+ const cssModule = tryParseCSSModule ( fileName ) ;
95+ if ( ! cssModule ) return ;
96+ cssModuleMap . set ( fileName , cssModule ) ;
97+
98+ // TODO: Delete only the minimum amount of check stage cache
99+ moduleResolutionCache . clear ( ) ;
100+ exportBuilder . clearCache ( ) ;
101+ semanticDiagnosticsMap . clear ( ) ;
102+ }
103+
104+ /**
105+ * @throws {ReadCSSModuleFileError }
106+ */
107+ function updateFile ( fileName : string ) {
108+ if ( ! cssModuleMap . has ( fileName ) ) return ;
109+
110+ const cssModule = tryParseCSSModule ( fileName ) ;
111+ if ( ! cssModule ) return ;
112+ cssModuleMap . set ( fileName , cssModule ) ;
113+
114+ // TODO: Delete only the minimum amount of check stage cache
115+ exportBuilder . clearCache ( ) ;
116+ semanticDiagnosticsMap . clear ( ) ;
117+
118+ emittedSet . delete ( fileName ) ;
119+ }
120+
121+ function removeFile ( fileName : string ) {
122+ if ( ! cssModuleMap . has ( fileName ) ) return ;
123+
124+ cssModuleMap . delete ( fileName ) ;
125+
126+ // TODO: Delete only the minimum amount of check stage cache
127+ moduleResolutionCache . clear ( ) ;
128+ exportBuilder . clearCache ( ) ;
129+ semanticDiagnosticsMap . delete ( fileName ) ;
130+
131+ emittedSet . delete ( fileName ) ;
85132 }
86133
87134 /**
@@ -119,7 +166,7 @@ export function createProject(args: ProjectArgs): Project {
119166 function getProjectDiagnostics ( ) {
120167 const diagnostics : Diagnostic [ ] = [ ] ;
121168 diagnostics . push ( ...config . diagnostics ) ;
122- if ( parseStageCache . size === 0 ) {
169+ if ( cssModuleMap . size === 0 ) {
123170 diagnostics . push ( {
124171 category : 'error' ,
125172 text : `The file specified in tsconfig.json not found.` ,
@@ -129,16 +176,16 @@ export function createProject(args: ProjectArgs): Project {
129176 }
130177
131178 function getSyntacticDiagnostics ( ) {
132- return Array . from ( parseStageCache . values ( ) ) . flatMap ( ( { diagnostics } ) => diagnostics ) ;
179+ return Array . from ( cssModuleMap . values ( ) ) . flatMap ( ( { diagnostics } ) => diagnostics ) ;
133180 }
134181
135182 function getSemanticDiagnostics ( ) {
136183 const allDiagnostics : Diagnostic [ ] = [ ] ;
137- for ( const cssModule of parseStageCache . values ( ) ) {
138- let diagnostics = checkStageCache . get ( cssModule . fileName ) ;
184+ for ( const cssModule of cssModuleMap . values ( ) ) {
185+ let diagnostics = semanticDiagnosticsMap . get ( cssModule . fileName ) ;
139186 if ( ! diagnostics ) {
140187 diagnostics = checkCSSModule ( cssModule , config , exportBuilder , matchesPattern , resolver , getCSSModule ) ;
141- checkStageCache . set ( cssModule . fileName , diagnostics ) ;
188+ semanticDiagnosticsMap . set ( cssModule . fileName , diagnostics ) ;
142189 }
143190 allDiagnostics . push ( ...diagnostics ) ;
144191 }
@@ -150,13 +197,16 @@ export function createProject(args: ProjectArgs): Project {
150197 */
151198 async function emitDtsFiles ( ) : Promise < void > {
152199 const promises : Promise < void > [ ] = [ ] ;
153- for ( const cssModule of parseStageCache . values ( ) ) {
200+ for ( const cssModule of cssModuleMap . values ( ) ) {
201+ if ( emittedSet . has ( cssModule . fileName ) ) continue ;
154202 const dts = generateDts ( cssModule , { resolver, matchesPattern } , { ...config , forTsPlugin : false } ) ;
155203 promises . push (
156204 writeDtsFile ( dts . text , cssModule . fileName , {
157205 outDir : config . dtsOutDir ,
158206 basePath : config . basePath ,
159207 arbitraryExtensions : config . arbitraryExtensions ,
208+ } ) . then ( ( ) => {
209+ emittedSet . add ( cssModule . fileName ) ;
160210 } ) ,
161211 ) ;
162212 }
@@ -165,6 +215,10 @@ export function createProject(args: ProjectArgs): Project {
165215
166216 return {
167217 config,
218+ isWildcardMatchedFile : ( fileName ) => matchesPattern ( fileName ) ,
219+ addFile,
220+ updateFile,
221+ removeFile,
168222 getDiagnostics,
169223 emitDtsFiles,
170224 } ;
0 commit comments