@@ -10,10 +10,13 @@ import { type PartialMessage, formatMessages } from 'esbuild';
1010import { existsSync } from 'node:fs' ;
1111import {
1212 type AngularCompilation ,
13+ DiagnosticModes ,
14+ type EmitFileResult ,
1315 createAngularCompilation ,
1416} from '../../../tools/angular/compilation' ;
1517import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets' ;
1618import { useTypeChecking } from '../../../utils/environment-options' ;
19+ import { assertIsError } from '../../../utils/error' ;
1720import { toPosixPath } from '../../../utils/path' ;
1821import type { BuilderState } from '../builder-state' ;
1922import type { LibraryCompilationOutput , NormalizedLibraryOptions } from '../types' ;
@@ -70,12 +73,22 @@ export async function compileLibrary(
7073
7174 if ( effectiveModifiedFiles && effectiveModifiedFiles . size > 0 ) {
7275 await compilationInstance . update ?.( effectiveModifiedFiles ) ;
73- buildState . clearFileReferences ( effectiveModifiedFiles ) ;
7476 }
7577
7678 const stylesheetWarnings : PartialMessage [ ] = [ ] ;
7779 const stylesheetErrors : PartialMessage [ ] = [ ] ;
7880 const failedFiles = new Set < string > ( ) ;
81+ const clearedReferenceFiles = new Set < string > ( ) ;
82+ const clearPreviousReferencesOnce = ( targetFile : string ) : void => {
83+ if ( ! cached ) {
84+ return ;
85+ }
86+ const posixTarget = toPosixPath ( targetFile ) ;
87+ if ( ! clearedReferenceFiles . has ( posixTarget ) ) {
88+ clearedReferenceFiles . add ( posixTarget ) ;
89+ buildState . clearFileReferences ( [ posixTarget ] ) ;
90+ }
91+ } ;
7992
8093 const hostOptions = {
8194 modifiedFiles : effectiveModifiedFiles ,
@@ -86,17 +99,23 @@ export async function compileLibrary(
8699 ) : Promise < string > {
87100 const result = stylesheetFile
88101 ? await stylesheetBundler . bundleFile ( stylesheetFile )
89- : await stylesheetBundler . bundleInline ( data , containingFile ) ;
90-
91- if ( result . referencedFiles ) {
92- buildState . addFileReferences ( stylesheetFile ?? containingFile , result . referencedFiles ) ;
93- }
102+ : await stylesheetBundler . bundleInline (
103+ data ,
104+ containingFile ,
105+ containingFile . endsWith ( '.html' ) ? 'css' : undefined ,
106+ ) ;
94107
95108 if ( result . warnings . length > 0 ) {
96109 stylesheetWarnings . push ( ...result . warnings ) ;
97110 }
98111
112+ const referenceTarget = stylesheetFile ?? containingFile ;
113+
99114 if ( result . errors ?. length ) {
115+ if ( result . referencedFiles ) {
116+ buildState . addFileReferences ( referenceTarget , result . referencedFiles ) ;
117+ }
118+
100119 stylesheetErrors . push ( ...result . errors ) ;
101120 failedFiles . add ( toPosixPath ( containingFile ) ) ;
102121 if ( stylesheetFile ) {
@@ -106,12 +125,22 @@ export async function compileLibrary(
106125 return '' ;
107126 }
108127
128+ clearPreviousReferencesOnce ( referenceTarget ) ;
129+
130+ if ( result . referencedFiles ) {
131+ buildState . addFileReferences ( referenceTarget , result . referencedFiles ) ;
132+ }
133+
109134 return result . contents ;
110135 } ,
111136 processWebWorker : ( ) => '' ,
112137 } ;
113138
114- const { referencedFiles, compilerOptions } = await compilationInstance . initialize (
139+ const {
140+ referencedFiles,
141+ compilerOptions,
142+ warnings : initWarnings ,
143+ } = await compilationInstance . initialize (
115144 tsConfigPath ,
116145 hostOptions ,
117146 {
@@ -126,6 +155,10 @@ export async function compileLibrary(
126155 'library' ,
127156 ) ;
128157
158+ if ( initWarnings ?. length ) {
159+ stylesheetWarnings . unshift ( ...initWarnings ) ;
160+ }
161+
129162 const hasStylesheetErrors = stylesheetErrors . length > 0 ;
130163 const emittedFiles = hasStylesheetErrors ? [ ] : await compilationInstance . emitAffectedFiles ( ) ;
131164 const diagnosePromise = runDiagnosticsAndFormat (
@@ -138,49 +171,14 @@ export async function compileLibrary(
138171
139172 const esmFiles = cached ?. esmFiles ?? new Map < string , string > ( ) ;
140173 const dtsFiles = cached ?. dtsFiles ?? new Map < string , string > ( ) ;
141- const changedEsmFiles = new Set < string > ( ) ;
142- const changedDtsFiles = new Set < string > ( ) ;
143174 const posixReferencedFiles = new Set ( referencedFiles . map ( toPosixPath ) ) ;
144-
145- if ( cached && effectiveModifiedFiles ) {
146- for ( const modifiedFile of effectiveModifiedFiles ) {
147- if ( posixReferencedFiles . has ( modifiedFile ) ) {
148- continue ;
149- }
150-
151- const basePathWithoutExt = modifiedFile . replace ( / (?: \. d \. [ c m ] ? t s | \. [ c m ] ? [ j t ] s x ? ) $ / i, '' ) ;
152- if ( basePathWithoutExt === modifiedFile || existsSync ( modifiedFile ) ) {
153- continue ;
154- }
155-
156- for ( const ext of EMITTED_EXTENSIONS ) {
157- const outputPath = `${ basePathWithoutExt } ${ ext } ` ;
158- const mapPath = `${ outputPath } .map` ;
159- if ( esmFiles . delete ( outputPath ) ) {
160- changedEsmFiles . add ( outputPath ) ;
161- }
162- if ( dtsFiles . delete ( outputPath ) ) {
163- changedDtsFiles . add ( outputPath ) ;
164- }
165- esmFiles . delete ( mapPath ) ;
166- dtsFiles . delete ( mapPath ) ;
167- }
168- }
169- }
170-
171- for ( const { filename, contents } of emittedFiles ) {
172- const normalized = toPosixPath ( filename ) ;
173- const isMap = normalized . endsWith ( '.map' ) ;
174- const isDts = isMap ? isDeclarationSourceMapFile ( normalized ) : isDeclarationFile ( normalized ) ;
175- const targetFiles = isDts ? dtsFiles : esmFiles ;
176-
177- if ( targetFiles . get ( normalized ) !== contents ) {
178- targetFiles . set ( normalized , contents ) ;
179- ( isDts ? changedDtsFiles : changedEsmFiles ) . add (
180- isMap ? normalized . slice ( 0 , - 4 ) : normalized ,
181- ) ;
182- }
183- }
175+ const { changedEsmFiles, changedDtsFiles } = updateEmittedFileCaches (
176+ emittedFiles ,
177+ esmFiles ,
178+ dtsFiles ,
179+ posixReferencedFiles ,
180+ cached ? effectiveModifiedFiles : undefined ,
181+ ) ;
184182
185183 return {
186184 esmFiles,
@@ -207,13 +205,75 @@ export async function compileLibrary(
207205 }
208206}
209207
208+ /**
209+ * Updates the in-memory ESM and DTS file maps with newly emitted files and prunes deleted
210+ * source files, returning the sets of changed ESM and DTS file paths.
211+ *
212+ * @param emittedFiles Newly emitted files from the Angular compilation.
213+ * @param esmFiles In-memory map of POSIX ESM file paths to contents.
214+ * @param dtsFiles In-memory map of POSIX declaration file paths to contents.
215+ * @param posixReferencedFiles Set of POSIX file paths currently referenced by the program.
216+ * @param modifiedFiles Optional set of modified POSIX file paths in incremental builds.
217+ * @returns Sets of changed ESM and DTS file paths.
218+ */
219+ function updateEmittedFileCaches (
220+ emittedFiles : Iterable < EmitFileResult > ,
221+ esmFiles : Map < string , string > ,
222+ dtsFiles : Map < string , string > ,
223+ posixReferencedFiles : ReadonlySet < string > ,
224+ modifiedFiles ?: ReadonlySet < string > ,
225+ ) : { changedEsmFiles : Set < string > ; changedDtsFiles : Set < string > } {
226+ const changedEsmFiles = new Set < string > ( ) ;
227+ const changedDtsFiles = new Set < string > ( ) ;
228+
229+ if ( modifiedFiles ) {
230+ for ( const modifiedFile of modifiedFiles ) {
231+ if ( posixReferencedFiles . has ( modifiedFile ) ) {
232+ continue ;
233+ }
234+
235+ const basePathWithoutExt = modifiedFile . replace ( / (?: \. d \. [ c m ] ? t s | \. [ c m ] ? [ j t ] s x ? ) $ / i, '' ) ;
236+ if ( basePathWithoutExt === modifiedFile || existsSync ( modifiedFile ) ) {
237+ continue ;
238+ }
239+
240+ for ( const ext of EMITTED_EXTENSIONS ) {
241+ const outputPath = `${ basePathWithoutExt } ${ ext } ` ;
242+ const mapPath = `${ outputPath } .map` ;
243+ if ( esmFiles . delete ( outputPath ) ) {
244+ changedEsmFiles . add ( outputPath ) ;
245+ }
246+ if ( dtsFiles . delete ( outputPath ) ) {
247+ changedDtsFiles . add ( outputPath ) ;
248+ }
249+ esmFiles . delete ( mapPath ) ;
250+ dtsFiles . delete ( mapPath ) ;
251+ }
252+ }
253+ }
254+
255+ for ( const { filename, contents } of emittedFiles ) {
256+ const normalized = toPosixPath ( filename ) ;
257+ const isMap = normalized . endsWith ( '.map' ) ;
258+ const isDts = isMap ? isDeclarationSourceMapFile ( normalized ) : isDeclarationFile ( normalized ) ;
259+ const targetFiles = isDts ? dtsFiles : esmFiles ;
260+
261+ if ( targetFiles . get ( normalized ) !== contents ) {
262+ targetFiles . set ( normalized , contents ) ;
263+ ( isDts ? changedDtsFiles : changedEsmFiles ) . add ( isMap ? normalized . slice ( 0 , - 4 ) : normalized ) ;
264+ }
265+ }
266+
267+ return { changedEsmFiles, changedDtsFiles } ;
268+ }
269+
210270/**
211271 * Formats stylesheet bundling diagnostics and TypeScript/Angular diagnostics
212272 * and records them on the build state's execution result.
213273 *
214274 * @param compilationInstance The active Angular compilation instance.
215275 * @param stylesheetErrors List of stylesheet bundling errors.
216- * @param stylesheetWarnings List of stylesheet bundling warnings.
276+ * @param stylesheetWarnings List of initialization and stylesheet bundling warnings.
217277 * @param colors Whether diagnostic messages should be formatted with ANSI colors.
218278 * @param buildState The build state whose execution result receives the formatted diagnostics.
219279 */
@@ -228,23 +288,39 @@ async function runDiagnosticsAndFormat(
228288 const errors = [ ...stylesheetErrors ] ;
229289 const warnings : PartialMessage [ ] = [ ] ;
230290
231- if ( errors . length === 0 && useTypeChecking ) {
232- const diagnostics = await compilationInstance . diagnoseFiles ( ) ;
291+ try {
292+ const diagnostics = await compilationInstance . diagnoseFiles (
293+ useTypeChecking ? DiagnosticModes . All : DiagnosticModes . All & ~ DiagnosticModes . Semantic ,
294+ ) ;
233295 if ( diagnostics . errors ?. length ) {
234296 errors . push ( ...diagnostics . errors ) ;
235297 }
236298 if ( diagnostics . warnings ?. length ) {
237299 warnings . push ( ...diagnostics . warnings ) ;
238300 }
301+ } catch ( error ) {
302+ assertIsError ( error ) ;
303+ errors . push ( {
304+ text : 'Angular compilation diagnostics failed.' ,
305+ location : null ,
306+ notes : [ { text : error . stack ?? error . message , location : null } ] ,
307+ } ) ;
239308 }
240309
241310 warnings . push ( ...stylesheetWarnings ) ;
242311
243- if ( errors . length > 0 ) {
244- executionResult . addErrors ( await formatMessages ( errors , { kind : 'error' , color : colors } ) ) ;
245- }
312+ try {
313+ if ( errors . length > 0 ) {
314+ executionResult . addErrors ( await formatMessages ( errors , { kind : 'error' , color : colors } ) ) ;
315+ }
246316
247- if ( warnings . length > 0 ) {
248- executionResult . addWarnings ( await formatMessages ( warnings , { kind : 'warning' , color : colors } ) ) ;
317+ if ( warnings . length > 0 ) {
318+ executionResult . addWarnings (
319+ await formatMessages ( warnings , { kind : 'warning' , color : colors } ) ,
320+ ) ;
321+ }
322+ } catch ( error ) {
323+ assertIsError ( error ) ;
324+ executionResult . addError ( error . message ) ;
249325 }
250326}
0 commit comments