diff --git a/Cargo.lock b/Cargo.lock index 2297370c2c48..a384de231394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4189,6 +4189,7 @@ dependencies = [ "rspack_hook", "rspack_javascript_compiler", "rspack_loader_runner", + "rspack_location", "rspack_macros", "rspack_napi", "rspack_paths", @@ -4232,6 +4233,7 @@ dependencies = [ "owo-colors", "rspack_cacheable", "rspack_collections", + "rspack_location", "rspack_paths", "serde_json", "swc_core", @@ -4428,6 +4430,14 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rspack_location" +version = "0.2.0" +dependencies = [ + "itoa", + "rspack_cacheable", +] + [[package]] name = "rspack_macros" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 9c09fef95dd9..173f0646da8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ indexmap = { version = "2.7.0" } indoc = { version = "2.0.5" } insta = { version = "1.42.0" } itertools = { version = "0.14.0" } +itoa = { version = "1.0.14" } json = { version = "0.12.4" } lightningcss = { version = "1.0.0-alpha.64", default-features = false, features = ["grid", "serde"] } linked_hash_set = { version = "0.1.5" } @@ -138,6 +139,7 @@ rspack_loader_react_refresh = { version = "0.2.0", path = "crates/rsp rspack_loader_runner = { version = "0.2.0", path = "crates/rspack_loader_runner" } rspack_loader_swc = { version = "0.2.0", path = "crates/rspack_loader_swc" } rspack_loader_testing = { version = "0.2.0", path = "crates/rspack_loader_testing" } +rspack_location = { version = "0.2.0", path = "crates/rspack_location" } rspack_macros = { version = "0.2.0", path = "crates/rspack_macros" } rspack_napi = { version = "0.2.0", path = "crates/rspack_napi" } rspack_napi_macros = { version = "0.2.0", path = "crates/rspack_napi_macros" } diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index ed0cc5e90765..54ad8008e021 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -73,6 +73,8 @@ export interface ContextModule extends Module { export interface ExternalModule extends Module { readonly userRequest: string; } + +export type DependencyLocation = SyntheticDependencyLocation | RealDependencyLocation; /* -- banner.d.ts end -- */ /* -- napi-rs generated below -- */ @@ -398,11 +400,7 @@ export declare class JsStats { } export declare class KnownBuildInfo { - get _assets(): Assets - get _fileDependencies(): Array - get _contextDependencies(): Array - get _missingDependencies(): Array - get _buildDependencies(): Array + } export declare class Module { @@ -678,7 +676,7 @@ export interface JsChunkAssetArgs { export interface JsChunkGroupOrigin { module?: Module | undefined request?: string - loc?: string | JsRealDependencyLocation + loc?: string | RealDependencyLocation } export interface JsChunkOptionNameCtx { @@ -958,11 +956,6 @@ export interface JsPathDataChunkLike { id?: string } -export interface JsRealDependencyLocation { - start: JsSourcePosition - end?: JsSourcePosition -} - export interface JsResolveArgs { request: string context: string @@ -1150,7 +1143,7 @@ export interface JsRspackError { name: string message: string moduleIdentifier?: string - loc?: string + loc?: DependencyLocation file?: string stack?: string hideStack?: boolean @@ -1187,11 +1180,6 @@ export interface JsRuntimeRequirementInTreeResult { allRuntimeRequirements: JsRuntimeGlobals } -export interface JsSourcePosition { - line: number - column: number -} - export interface JsStatsAsset { type: string name: string @@ -2574,6 +2562,11 @@ export interface RawTrustedTypes { onPolicyCreationFailure?: string } +export interface RealDependencyLocation { + start: SourcePosition + end?: SourcePosition +} + /** * Some code is modified based on * https://github.com/swc-project/swc/blob/d1d0607158ab40463d1b123fed52cc526eba8385/bindings/binding_core_node/src/util.rs#L29-L58 @@ -2713,6 +2706,11 @@ export interface SourceMapDevToolPluginOptions { debugIds?: boolean } +export interface SourcePosition { + line: number + column?: number +} + /** * Start the async runtime manually. * @@ -2721,6 +2719,10 @@ export interface SourceMapDevToolPluginOptions { */ export declare function startAsyncRuntime(): void +export interface SyntheticDependencyLocation { + name: string +} + export interface ThreadsafeNodeFS { writeFile: (name: string, content: Buffer) => Promise removeFile: (name: string) => Promise diff --git a/crates/node_binding/scripts/banner.d.ts b/crates/node_binding/scripts/banner.d.ts index 29e7cae0e1b5..db874cfca7d0 100644 --- a/crates/node_binding/scripts/banner.d.ts +++ b/crates/node_binding/scripts/banner.d.ts @@ -73,6 +73,8 @@ export interface ContextModule extends Module { export interface ExternalModule extends Module { readonly userRequest: string; } + +export type DependencyLocation = SyntheticDependencyLocation | RealDependencyLocation; /* -- banner.d.ts end -- */ /* -- napi-rs generated below -- */ diff --git a/crates/node_binding/src/chunk_group.rs b/crates/node_binding/src/chunk_group.rs index 216ac8f356a5..3b6920c0f044 100644 --- a/crates/node_binding/src/chunk_group.rs +++ b/crates/node_binding/src/chunk_group.rs @@ -2,14 +2,11 @@ use std::{cell::RefCell, ptr::NonNull}; use napi::{bindgen_prelude::ToNapiValue, Either, Env, JsString}; use napi_derive::napi; -use rspack_core::{ - ChunkGroup, ChunkGroupUkey, Compilation, CompilationId, DependencyLocation, - RealDependencyLocation, SourcePosition, -}; +use rspack_core::{ChunkGroup, ChunkGroupUkey, Compilation, CompilationId}; use rspack_napi::OneShotRef; use rustc_hash::FxHashMap as HashMap; -use crate::{JsChunkWrapper, ModuleObject, ModuleObjectRef}; +use crate::{location::RealDependencyLocation, JsChunkWrapper, ModuleObject, ModuleObjectRef}; #[napi] pub struct JsChunkGroup { @@ -72,8 +69,8 @@ impl JsChunkGroup { for origin in origins { let loc = if let Some(loc) = &origin.loc { Some(match loc { - DependencyLocation::Real(real) => Either::B(real.clone().into()), - DependencyLocation::Synthetic(synthetic) => { + rspack_core::DependencyLocation::Real(real) => Either::B(real.into()), + rspack_core::DependencyLocation::Synthetic(synthetic) => { Either::A(env.create_string(&synthetic.name)?) } }) @@ -248,34 +245,5 @@ pub struct JsChunkGroupOrigin<'a> { #[napi(ts_type = "Module | undefined")] pub module: Option, pub request: Option>, - pub loc: Option, JsRealDependencyLocation>>, -} - -#[napi(object, object_from_js = false)] -pub struct JsRealDependencyLocation { - pub start: JsSourcePosition, - pub end: Option, -} - -impl From for JsRealDependencyLocation { - fn from(value: RealDependencyLocation) -> Self { - Self { - start: value.start.into(), - end: value.end.map(JsSourcePosition::from), - } - } -} -#[napi(object, object_from_js = false)] -pub struct JsSourcePosition { - pub line: u32, - pub column: u32, -} - -impl From for JsSourcePosition { - fn from(value: SourcePosition) -> Self { - Self { - line: value.line as u32, - column: value.column as u32, - } - } + pub loc: Option, RealDependencyLocation>>, } diff --git a/crates/node_binding/src/diagnostic.rs b/crates/node_binding/src/diagnostic.rs index 2a0ff218c538..d6e4c74418ad 100644 --- a/crates/node_binding/src/diagnostic.rs +++ b/crates/node_binding/src/diagnostic.rs @@ -95,7 +95,18 @@ pub fn format_diagnostic(diagnostic: JsDiagnostic) -> Result, - pub loc: Option, + pub loc: Option, pub file: Option, pub stack: Option, pub hide_stack: Option, @@ -84,7 +86,7 @@ impl JsRspackError { }), message, module_identifier: diagnostic.module_identifier().map(|d| d.to_string()), - loc: diagnostic.loc(), + loc: diagnostic.loc().map(Into::into), file: diagnostic.file().map(|f| f.as_str().to_string()), stack: diagnostic.stack(), hide_stack: diagnostic.hide_stack(), diff --git a/crates/node_binding/src/lib.rs b/crates/node_binding/src/lib.rs index e26b32724d68..b1e4ed42c835 100644 --- a/crates/node_binding/src/lib.rs +++ b/crates/node_binding/src/lib.rs @@ -43,6 +43,7 @@ mod filename; mod fs_node; mod html; mod identifier; +mod location; mod module; mod module_graph; mod module_graph_connection; @@ -83,6 +84,7 @@ pub use error::*; pub use exports_info::*; pub use filename::*; pub use html::*; +pub use location::*; pub use module::*; pub use module_graph::*; pub use module_graph_connection::*; diff --git a/crates/node_binding/src/location.rs b/crates/node_binding/src/location.rs new file mode 100644 index 000000000000..5d069383cf2d --- /dev/null +++ b/crates/node_binding/src/location.rs @@ -0,0 +1,138 @@ +use std::fmt::Debug; + +use napi::bindgen_prelude::{FromNapiValue, ToNapiValue}; + +#[napi(object)] +#[derive(Debug)] +pub struct SourcePosition { + pub line: u32, + pub column: Option, +} + +impl From<&rspack_core::SourcePosition> for SourcePosition { + fn from(value: &rspack_core::SourcePosition) -> Self { + Self { + line: value.line as u32, + column: Some(value.column as u32), + } + } +} + +impl From for SourcePosition { + fn from(value: rspack_core::SourcePosition) -> Self { + Self { + line: value.line as u32, + column: Some(value.column as u32), + } + } +} + +#[napi(object)] +#[derive(Debug)] +pub struct RealDependencyLocation { + pub start: SourcePosition, + pub end: Option, +} + +impl From<&rspack_core::RealDependencyLocation> for RealDependencyLocation { + fn from(value: &rspack_core::RealDependencyLocation) -> Self { + Self { + start: value.start.into(), + end: value.end.map(Into::into), + } + } +} + +impl From for RealDependencyLocation { + fn from(value: rspack_core::RealDependencyLocation) -> Self { + Self { + start: value.start.into(), + end: value.end.map(Into::into), + } + } +} + +#[napi(object)] +#[derive(Debug)] +pub struct SyntheticDependencyLocation { + pub name: String, +} + +impl From<&rspack_core::SyntheticDependencyLocation> for SyntheticDependencyLocation { + fn from(value: &rspack_core::SyntheticDependencyLocation) -> Self { + Self { + name: value.name.to_string(), + } + } +} + +impl From for SyntheticDependencyLocation { + fn from(value: rspack_core::SyntheticDependencyLocation) -> Self { + Self { name: value.name } + } +} + +#[derive(Debug)] +pub enum DependencyLocation { + Real(RealDependencyLocation), + Synthetic(SyntheticDependencyLocation), +} + +impl ToNapiValue for DependencyLocation { + unsafe fn to_napi_value( + env: napi::sys::napi_env, + val: Self, + ) -> napi::Result { + match val { + DependencyLocation::Real(real_dependency_location) => { + ToNapiValue::to_napi_value(env, real_dependency_location) + } + DependencyLocation::Synthetic(synthetic_dependency_location) => { + ToNapiValue::to_napi_value(env, synthetic_dependency_location) + } + } + } +} + +impl FromNapiValue for DependencyLocation { + unsafe fn from_napi_value( + env: napi::sys::napi_env, + napi_val: napi::sys::napi_value, + ) -> napi::Result { + let obj = napi::bindgen_prelude::Object::from_napi_value(env, napi_val)?; + if let Ok(Some(name)) = obj.get::("name") { + return Ok(DependencyLocation::Synthetic(SyntheticDependencyLocation { + name, + })); + }; + let real_dependency_location: RealDependencyLocation = + FromNapiValue::from_napi_value(env, napi_val)?; + Ok(DependencyLocation::Real(real_dependency_location)) + } +} + +impl From<&rspack_core::DependencyLocation> for DependencyLocation { + fn from(value: &rspack_core::DependencyLocation) -> Self { + match value { + rspack_core::DependencyLocation::Real(real_dependency_location) => { + DependencyLocation::Real(real_dependency_location.into()) + } + rspack_core::DependencyLocation::Synthetic(synthetic_dependency_location) => { + DependencyLocation::Synthetic(synthetic_dependency_location.into()) + } + } + } +} + +impl From for DependencyLocation { + fn from(value: rspack_core::DependencyLocation) -> Self { + match value { + rspack_core::DependencyLocation::Real(real_dependency_location) => { + DependencyLocation::Real(real_dependency_location.into()) + } + rspack_core::DependencyLocation::Synthetic(synthetic_dependency_location) => { + DependencyLocation::Synthetic(synthetic_dependency_location.into()) + } + } + } +} diff --git a/crates/rspack_core/Cargo.toml b/crates/rspack_core/Cargo.toml index 63084422e698..d71c925c8b64 100644 --- a/crates/rspack_core/Cargo.toml +++ b/crates/rspack_core/Cargo.toml @@ -42,6 +42,7 @@ rspack_hash = { workspace = true } rspack_hook = { workspace = true } rspack_javascript_compiler = { workspace = true } rspack_loader_runner = { workspace = true } +rspack_location = { workspace = true } rspack_macros = { workspace = true } rspack_napi = { workspace = true, optional = true } rspack_paths = { workspace = true } diff --git a/crates/rspack_core/src/compiler/make/repair/factorize.rs b/crates/rspack_core/src/compiler/make/repair/factorize.rs index 9cd92f609d76..c9fbde0fb483 100644 --- a/crates/rspack_core/src/compiler/make/repair/factorize.rs +++ b/crates/rspack_core/src/compiler/make/repair/factorize.rs @@ -94,8 +94,7 @@ impl Task for FactorizeTask { } create_data.diagnostics.insert( 0, - Into::::into(e) - .with_loc(create_data.dependencies[0].loc().map(|loc| loc.to_string())), + Into::::into(e).with_loc(create_data.dependencies[0].loc()), ); None } diff --git a/crates/rspack_core/src/dependency/dependency_location.rs b/crates/rspack_core/src/dependency/dependency_location.rs index a6bd565145e6..ce5c5325e8d1 100644 --- a/crates/rspack_core/src/dependency/dependency_location.rs +++ b/crates/rspack_core/src/dependency/dependency_location.rs @@ -4,7 +4,7 @@ use std::{ }; use rspack_cacheable::cacheable; -use rspack_util::itoa; +use rspack_location::{DependencyLocation, RealDependencyLocation, SourcePosition}; /// Represents a range in a dependency, typically used for tracking the span of code in a source file. /// It stores the start and end positions (as offsets) of the range, typically using base-0 indexing. @@ -53,103 +53,6 @@ impl DependencyRange { } } -/// Represents the real location of a dependency in a source file, including both start and optional end positions. -/// These positions are described in terms of lines and columns in the source code. -#[cacheable] -#[derive(Debug, Clone)] -pub struct RealDependencyLocation { - pub start: SourcePosition, - pub end: Option, -} - -impl RealDependencyLocation { - pub fn new(start: SourcePosition, end: Option) -> Self { - Self { start, end } - } -} - -impl fmt::Display for RealDependencyLocation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(end) = self.end { - if self.start.line == end.line { - write!( - f, - "{}:{}-{}", - itoa!(self.start.line), - itoa!(self.start.column), - itoa!(end.column) - ) - } else { - write!( - f, - "{}:{}-{}:{}", - itoa!(self.start.line), - itoa!(self.start.column), - itoa!(end.line), - itoa!(end.column) - ) - } - } else { - write!(f, "{}:{}", itoa!(self.start.line), itoa!(self.start.column)) - } - } -} - -/// Represents a synthetic dependency location, such as a generated dependency. -#[cacheable] -#[derive(Debug, Clone)] -pub struct SyntheticDependencyLocation { - pub name: String, -} - -impl SyntheticDependencyLocation { - pub fn new(name: &str) -> Self { - SyntheticDependencyLocation { - name: name.to_string(), - } - } -} - -impl fmt::Display for SyntheticDependencyLocation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -#[cacheable] -#[derive(Debug, Clone)] -pub enum DependencyLocation { - Real(RealDependencyLocation), - Synthetic(SyntheticDependencyLocation), -} - -impl fmt::Display for DependencyLocation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let loc = match self { - DependencyLocation::Real(real) => real.to_string(), - DependencyLocation::Synthetic(synthetic) => synthetic.to_string(), - }; - write!(f, "{loc}") - } -} - -/// Represents a position in the source file, including the line number and column number. -#[cacheable] -#[derive(Debug, Clone, Copy)] -pub struct SourcePosition { - pub line: usize, - pub column: usize, -} - -impl From<(u32, u32)> for SourcePosition { - fn from(range: (u32, u32)) -> Self { - Self { - line: range.0 as usize, - column: range.1 as usize, - } - } -} - /// Trait representing a source map that can resolve the positions of code ranges to source file positions. pub trait SourceLocation: Send + Sync { fn look_up_range_pos(&self, start: u32, end: u32) -> Option<(SourcePosition, SourcePosition)>; diff --git a/crates/rspack_core/src/dependency/dependency_trait.rs b/crates/rspack_core/src/dependency/dependency_trait.rs index 6f2dbc3efd56..da4109cfe87e 100644 --- a/crates/rspack_core/src/dependency/dependency_trait.rs +++ b/crates/rspack_core/src/dependency/dependency_trait.rs @@ -8,11 +8,12 @@ use rspack_util::{atom::Atom, ext::AsAny}; use super::{ dependency_template::AsDependencyCodeGeneration, module_dependency::*, DependencyCategory, - DependencyId, DependencyLocation, DependencyRange, DependencyType, ExportsSpec, + DependencyId, DependencyRange, DependencyType, ExportsSpec, }; use crate::{ create_exports_object_referenced, AsContextDependency, ConnectionState, Context, - ExtendedReferencedExport, ImportAttributes, ModuleGraph, ModuleLayer, RuntimeSpec, UsedByExports, + DependencyLocation, ExtendedReferencedExport, ImportAttributes, ModuleGraph, ModuleLayer, + RuntimeSpec, UsedByExports, }; #[derive(Debug, Clone, Copy)] diff --git a/crates/rspack_core/src/lib.rs b/crates/rspack_core/src/lib.rs index 816351207d10..fb8ca800596f 100644 --- a/crates/rspack_core/src/lib.rs +++ b/crates/rspack_core/src/lib.rs @@ -96,6 +96,9 @@ mod ukey; pub use ukey::*; pub mod resolver; pub use resolver::*; +pub use rspack_location::{ + DependencyLocation, RealDependencyLocation, SourcePosition, SyntheticDependencyLocation, +}; pub mod concatenated_module; pub mod reserved_names; diff --git a/crates/rspack_core/src/stats/mod.rs b/crates/rspack_core/src/stats/mod.rs index 0810e2c92072..d4fe22da1403 100644 --- a/crates/rspack_core/src/stats/mod.rs +++ b/crates/rspack_core/src/stats/mod.rs @@ -625,7 +625,7 @@ impl Stats<'_> { module_identifier, module_name, module_id: module_id.flatten(), - loc: d.loc(), + loc: d.loc().map(|loc| loc.to_string()), file: d.file(), chunk_name: chunk.and_then(|c| c.name()), @@ -688,7 +688,7 @@ impl Stats<'_> { module_identifier, module_name, module_id: module_id.flatten(), - loc: d.loc(), + loc: d.loc().map(|loc| loc.to_string()), file: d.file(), chunk_name: chunk.and_then(|c| c.name()), diff --git a/crates/rspack_error/Cargo.toml b/crates/rspack_error/Cargo.toml index 50b4e8f7d600..fac674076215 100644 --- a/crates/rspack_error/Cargo.toml +++ b/crates/rspack_error/Cargo.toml @@ -17,6 +17,7 @@ once_cell = { workspace = true } owo-colors = "4.0.0" rspack_cacheable = { workspace = true } rspack_collections = { workspace = true } +rspack_location = { workspace = true } rspack_paths = { workspace = true } serde_json = { workspace = true } swc_core = { workspace = true, features = ["common", "common_concurrent"] } diff --git a/crates/rspack_error/src/diagnostic.rs b/crates/rspack_error/src/diagnostic.rs index 658bacee7b80..505ebb6e5dc8 100644 --- a/crates/rspack_error/src/diagnostic.rs +++ b/crates/rspack_error/src/diagnostic.rs @@ -4,8 +4,8 @@ use cow_utils::CowUtils; use miette::{GraphicalTheme, IntoDiagnostic, MietteDiagnostic}; use rspack_cacheable::{cacheable, with::Unsupported}; use rspack_collections::Identifier; +use rspack_location::DependencyLocation; use rspack_paths::{Utf8Path, Utf8PathBuf}; -use swc_core::common::{SourceMap, Span}; use crate::{graphical::GraphicalReportHandler, Error}; @@ -60,44 +60,12 @@ impl fmt::Display for RspackSeverity { } } -#[cacheable] -#[derive(Debug, Clone, Copy)] -pub struct SourcePosition { - pub line: usize, - pub column: usize, -} - -#[cacheable] -#[derive(Debug, Clone, Copy)] -pub struct ErrorLocation { - pub start: SourcePosition, - pub end: SourcePosition, -} - -impl ErrorLocation { - pub fn new(span: Span, source_map: &SourceMap) -> Self { - let lo = source_map.lookup_char_pos(span.lo()); - let hi = source_map.lookup_char_pos(span.hi()); - - ErrorLocation { - start: SourcePosition { - line: lo.line, - column: lo.col_display, - }, - end: SourcePosition { - line: hi.line, - column: hi.col_display, - }, - } - } -} - #[cacheable(with=Unsupported)] #[derive(Debug, Clone)] pub struct Diagnostic { inner: Arc, module_identifier: Option, - loc: Option, + loc: Option, file: Option, hide_stack: Option, chunk: Option, @@ -200,11 +168,11 @@ impl Diagnostic { self } - pub fn loc(&self) -> Option { - self.loc.clone() + pub fn loc(&self) -> Option<&DependencyLocation> { + self.loc.as_ref() } - pub fn with_loc(mut self, loc: Option) -> Self { + pub fn with_loc(mut self, loc: Option) -> Self { self.loc = loc; self } diff --git a/crates/rspack_location/Cargo.toml b/crates/rspack_location/Cargo.toml new file mode 100644 index 000000000000..5d28544fbda6 --- /dev/null +++ b/crates/rspack_location/Cargo.toml @@ -0,0 +1,11 @@ +[package] +description = "rspack location" +edition.workspace = true +license = "MIT" +name = "rspack_location" +repository = "https://github.com/web-infra-dev/rspack" +version = "0.2.0" + +[dependencies] +itoa = { workspace = true } +rspack_cacheable = { workspace = true } diff --git a/crates/rspack_location/LICENSE b/crates/rspack_location/LICENSE new file mode 100644 index 000000000000..46310101ad8a --- /dev/null +++ b/crates/rspack_location/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2022-present Bytedance, Inc. and its affiliates. + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/rspack_location/src/lib.rs b/crates/rspack_location/src/lib.rs new file mode 100644 index 000000000000..49a04194d9d8 --- /dev/null +++ b/crates/rspack_location/src/lib.rs @@ -0,0 +1,110 @@ +use std::fmt::{self, Debug}; + +pub use itoa::Buffer; +use rspack_cacheable::cacheable; + +#[macro_export] +macro_rules! itoa { + ($i:expr) => {{ + itoa::Buffer::new().format($i) + }}; +} + +/// Represents a position in the source file, including the line number and column number. +#[cacheable] +#[derive(Debug, Clone, Copy)] +pub struct SourcePosition { + pub line: usize, + pub column: usize, +} + +impl From<(u32, u32)> for SourcePosition { + fn from(range: (u32, u32)) -> Self { + Self { + line: range.0 as usize, + column: range.1 as usize, + } + } +} + +/// Represents the real location of a dependency in a source file, including both start and optional end positions. +/// These positions are described in terms of lines and columns in the source code. +#[cacheable] +#[derive(Debug, Clone)] +pub struct RealDependencyLocation { + pub start: SourcePosition, + pub end: Option, +} + +impl RealDependencyLocation { + pub fn new(start: SourcePosition, end: Option) -> Self { + Self { start, end } + } +} + +impl fmt::Display for RealDependencyLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(end) = self.end { + if self.start.line == end.line && self.start.column == end.column { + write!(f, "{}:{}", itoa!(self.start.line), itoa!(self.start.column)) + } else if self.start.line == end.line { + write!( + f, + "{}:{}-{}", + itoa!(self.start.line), + itoa!(self.start.column), + itoa!(end.column) + ) + } else { + write!( + f, + "{}:{}-{}:{}", + itoa!(self.start.line), + itoa!(self.start.column), + itoa!(end.line), + itoa!(end.column) + ) + } + } else { + write!(f, "{}:{}", itoa!(self.start.line), itoa!(self.start.column)) + } + } +} + +/// Represents a synthetic dependency location, such as a generated dependency. +#[cacheable] +#[derive(Debug, Clone)] +pub struct SyntheticDependencyLocation { + pub name: String, +} + +impl SyntheticDependencyLocation { + pub fn new(name: &str) -> Self { + SyntheticDependencyLocation { + name: name.to_string(), + } + } +} + +impl fmt::Display for SyntheticDependencyLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +#[cacheable] +#[derive(Debug, Clone)] +pub enum DependencyLocation { + Real(RealDependencyLocation), + Synthetic(SyntheticDependencyLocation), +} + +impl fmt::Display for DependencyLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let loc = match self { + DependencyLocation::Real(real) => real.to_string(), + DependencyLocation::Synthetic(synthetic) => synthetic.to_string(), + }; + write!(f, "{loc}") + } +} diff --git a/crates/rspack_util/Cargo.toml b/crates/rspack_util/Cargo.toml index f784777b13c8..654e9f513cec 100644 --- a/crates/rspack_util/Cargo.toml +++ b/crates/rspack_util/Cargo.toml @@ -14,7 +14,7 @@ concat-string = { workspace = true } cow-utils = { workspace = true } dashmap = { workspace = true } indexmap = { workspace = true } -itoa = { version = "1.0.14" } +itoa = { workspace = true } regex = { workspace = true } ropey = { workspace = true } rspack_cacheable = { workspace = true } diff --git a/packages/rspack-test-tools/tests/errorCases/error-map.js b/packages/rspack-test-tools/tests/errorCases/error-map.js index 1aa83177d1bb..0608f7bc3aaf 100644 --- a/packages/rspack-test-tools/tests/errorCases/error-map.js +++ b/packages/rspack-test-tools/tests/errorCases/error-map.js @@ -24,7 +24,16 @@ module.exports = { Array [ Object { "index": 0, - "loc": "1:0-33", + "loc": Object { + "end": Object { + "column": 33, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, "message": " × Module not found: Can't resolve './answer' in '/tests/fixtures/errors/resolve-fail-esm'\\n ╭────\\n 1 │ import { answer } from './answer'\\n · ──────────\\n ╰────\\n help: Did you mean './answer.js'?\\n \\n The request './answer' failed to resolve only because it was resolved as fully specified,\\n probably because the origin is strict EcmaScript Module,\\n e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '\\"type\\": \\"module\\"'.\\n \\n The extension in the request is mandatory for it to be fully specified.\\n Add the extension to the request.\\n", "moduleIdentifier": "javascript/esm|/tests/fixtures/errors/resolve-fail-esm/index.js", "name": "Error", diff --git a/packages/rspack/src/util/index.ts b/packages/rspack/src/util/index.ts index 994b5ca57388..6eb115f5e6d0 100644 --- a/packages/rspack/src/util/index.ts +++ b/packages/rspack/src/util/index.ts @@ -74,10 +74,6 @@ export function concatErrorMsgAndStack( // maybe `null`, use `undefined` to compatible with `Option` err.stack = err.stack || undefined; - if ("loc" in err) { - err.loc = JSON.stringify(err.loc); - } - return err; }