@@ -2,12 +2,12 @@ use std::{collections::VecDeque, sync::Arc};
22
33use rspack_core:: {
44 Compilation , DependencyCategory , IsolatedDts , Resolve , ResolveOptionsWithDependencyType ,
5- ResolveResult , TsconfigOptions , TsconfigReferences ,
5+ ResolveResult , TsconfigOptions , TsconfigReferences , diagnostics :: ModuleBuildError ,
66} ;
7- use rspack_error:: { Result , error } ;
7+ use rspack_error:: { Diagnostic , Error , Result } ;
88use rspack_javascript_compiler:: JavaScriptCompiler ;
99use rspack_paths:: { Utf8Path , Utf8PathBuf } ;
10- use rspack_util:: node_path:: NodePath ;
10+ use rspack_util:: { identifier :: absolute_to_request , node_path:: NodePath } ;
1111use rustc_hash:: FxHashSet as HashSet ;
1212use swc_core:: {
1313 common:: FileName ,
@@ -24,6 +24,11 @@ pub(crate) struct IsolatedDtsAsset {
2424 pub code : String ,
2525}
2626
27+ pub ( crate ) struct CompletedIsolatedDtsOutputs {
28+ pub assets : Vec < IsolatedDtsAsset > ,
29+ pub diagnostics : Vec < Diagnostic > ,
30+ }
31+
2732struct IsolatedDtsReferences {
2833 issuer_resource_path : String ,
2934 references : Vec < String > ,
@@ -33,12 +38,17 @@ pub(crate) async fn complete_isolated_dts_outputs(
3338 compilation : & mut Compilation ,
3439 options : & SwcEmitDtsOptions ,
3540 roots : Vec < IsolatedDts > ,
36- ) -> Result < Vec < IsolatedDtsAsset > > {
41+ module_resources : Vec < Utf8PathBuf > ,
42+ ) -> Result < CompletedIsolatedDtsOutputs > {
3743 if roots. is_empty ( ) {
38- return Ok ( Vec :: new ( ) ) ;
44+ return Ok ( CompletedIsolatedDtsOutputs {
45+ assets : Vec :: new ( ) ,
46+ diagnostics : Vec :: new ( ) ,
47+ } ) ;
3948 }
4049
4150 let mut outputs = Vec :: with_capacity ( roots. len ( ) ) ;
51+ let mut diagnostics = Vec :: new ( ) ;
4252 let mut queue = VecDeque :: with_capacity ( roots. len ( ) ) ;
4353
4454 for IsolatedDts {
@@ -61,7 +71,10 @@ pub(crate) async fn complete_isolated_dts_outputs(
6171 }
6272
6373 if queue. is_empty ( ) {
64- return Ok ( outputs) ;
74+ return Ok ( CompletedIsolatedDtsOutputs {
75+ assets : outputs,
76+ diagnostics,
77+ } ) ;
6578 }
6679
6780 let compiler_root = compilation. options . context . as_path ( ) . to_path_buf ( ) ;
@@ -76,10 +89,14 @@ pub(crate) async fn complete_isolated_dts_outputs(
7689 dependency_category : DependencyCategory :: Esm ,
7790 } ) ;
7891 let mut javascript_compiler = None ;
79- let mut seen: HashSet < Utf8PathBuf > = outputs
80- . iter ( )
81- . map ( |output| resolve_path ( & compiler_root, & output. resource_path ) )
82- . collect ( ) ;
92+ // Reference completion should only generate files that are absent from the
93+ // normal module graph; normal module builds already own their dts diagnostics.
94+ let mut completed_resources: HashSet < Utf8PathBuf > = module_resources. into_iter ( ) . collect ( ) ;
95+ completed_resources. extend (
96+ outputs
97+ . iter ( )
98+ . map ( |output| resolve_path ( & compiler_root, & output. resource_path ) ) ,
99+ ) ;
83100
84101 while let Some ( IsolatedDtsReferences {
85102 issuer_resource_path,
@@ -115,10 +132,13 @@ pub(crate) async fn complete_isolated_dts_outputs(
115132 continue ;
116133 }
117134
118- if !seen . insert ( resource_path. clone ( ) ) {
135+ if !completed_resources . insert ( resource_path. clone ( ) ) {
119136 continue ;
120137 }
121138
139+ let diagnostic_file = Utf8PathBuf :: from (
140+ absolute_to_request ( compiler_root. as_str ( ) , resource_path. as_str ( ) ) . into_owned ( ) ,
141+ ) ;
122142 let std_resource_path = resource_path. clone ( ) . into_std_path_buf ( ) ;
123143 compilation
124144 . file_dependencies
@@ -141,7 +161,24 @@ pub(crate) async fn complete_isolated_dts_outputs(
141161 syntax,
142162 EsVersion :: EsNext ,
143163 ) ?;
144- handle_isolated_dts_diagnostics ( & resource_path, dts_output. diagnostics ) ?;
164+ let mut dts_diagnostics = dts_output. diagnostics . into_iter ( ) ;
165+ if let Some ( first) = dts_diagnostics. next ( ) {
166+ let mut source_error = Error :: error ( first) ;
167+ source_error. code = Some ( "RslibPlugin" . into ( ) ) ;
168+
169+ let mut dts_error = Error :: error ( "Failed to generate declaration files." . to_string ( ) ) ;
170+ dts_error. code = Some ( "RslibPlugin" . into ( ) ) ;
171+ dts_error. source_error = Some ( Box :: new ( source_error) ) ;
172+ let remaining = dts_diagnostics. collect :: < Vec < _ > > ( ) ;
173+ if !remaining. is_empty ( ) {
174+ dts_error. help = Some ( remaining. join ( "\n " ) ) ;
175+ }
176+
177+ let mut diagnostic: Diagnostic = Error :: from ( ModuleBuildError :: new ( dts_error, None ) ) . into ( ) ;
178+ diagnostic. file = Some ( diagnostic_file) ;
179+ diagnostics. push ( diagnostic) ;
180+ continue ;
181+ }
145182
146183 let has_references = !dts_output. references . is_empty ( ) ;
147184 let resource_path = resource_path. as_str ( ) . to_string ( ) ;
@@ -158,7 +195,10 @@ pub(crate) async fn complete_isolated_dts_outputs(
158195 }
159196 }
160197
161- Ok ( outputs)
198+ Ok ( CompletedIsolatedDtsOutputs {
199+ assets : outputs,
200+ diagnostics,
201+ } )
162202}
163203
164204fn resolve_path ( base : & Utf8Path , value : & str ) -> Utf8PathBuf {
@@ -231,24 +271,3 @@ fn type_resolve_options(tsconfig: Option<TsconfigOptions>) -> Resolve {
231271 ..Default :: default ( )
232272 }
233273}
234-
235- fn handle_isolated_dts_diagnostics (
236- resource_path : & Utf8Path ,
237- diagnostics : Vec < String > ,
238- ) -> Result < ( ) > {
239- let mut diagnostics = diagnostics. into_iter ( ) ;
240- let Some ( first) = diagnostics. next ( ) else {
241- return Ok ( ( ) ) ;
242- } ;
243- let remaining = diagnostics. collect :: < Vec < _ > > ( ) ;
244- let help = if remaining. is_empty ( ) {
245- String :: new ( )
246- } else {
247- format ! ( "\n {}" , remaining. join( "\n " ) )
248- } ;
249-
250- Err ( error ! (
251- "Failed to generate declaration files for {}.\n {}{}" ,
252- resource_path, first, help
253- ) )
254- }
0 commit comments