@@ -6,58 +6,51 @@ use std::{
66 sync:: Arc ,
77} ;
88
9- use nodejs_package_json:: {
10- BrowserField , ImportExportField , ImportExportMap , PackageJson as BasePackageJson ,
11- } ;
12- use rustc_hash:: FxHashMap ;
9+ use nodejs_package_json:: { BrowserField , ImportExportField , ImportExportMap } ;
1310use serde:: Deserialize ;
1411use serde_json:: Value ;
1512
1613use crate :: { path:: PathUtil , ResolveError , ResolveOptions } ;
1714
1815/// Deserialized package.json
19- #[ derive( Debug , Default , Deserialize ) ]
16+ #[ derive( Debug , Default ) ]
2017pub struct PackageJson {
2118 /// Path to `package.json`. Contains the `package.json` filename.
22- #[ serde( skip) ]
2319 pub path : PathBuf ,
2420
2521 /// Realpath to `package.json`. Contains the `package.json` filename.
26- #[ serde( skip) ]
2722 pub realpath : PathBuf ,
2823
29- #[ serde( skip) ]
3024 pub ( crate ) raw_json : Arc < serde_json:: Value > ,
3125
32- /// The deserialized `package.json`.
33- pub data : BasePackageJson ,
26+ /// The "name" field defines your package's name.
27+ /// The "name" field can be used in addition to the "exports" field to self-reference a package using its name.
28+ ///
29+ /// <https://nodejs.org/api/packages.html#name>
30+ pub name : Option < String > ,
3431
3532 /// The "main" field defines the entry point of a package when imported by name via a node_modules lookup. Its value is a path.
3633 /// When a package has an "exports" field, this will take precedence over the "main" field when importing the package by name.
3734 ///
3835 /// Values are dynamically added from [ResolveOptions::main_fields].
3936 ///
4037 /// <https://nodejs.org/api/packages.html#main>
41- #[ serde( skip) ]
4238 pub main_fields : Vec < String > ,
4339
4440 /// The "exports" field allows defining the entry points of a package when imported by name loaded either via a node_modules lookup or a self-reference to its own name.
4541 ///
4642 /// <https://nodejs.org/api/packages.html#exports>
47- #[ serde( skip) ]
4843 pub exports : Vec < ImportExportField > ,
4944
5045 /// In addition to the "exports" field, there is a package "imports" field to create private mappings that only apply to import specifiers from within the package itself.
5146 ///
5247 /// <https://nodejs.org/api/packages.html#subpath-imports>
53- #[ serde( default ) ]
54- pub imports : Box < ImportExportMap > ,
48+ pub imports : Option < Box < ImportExportMap > > ,
5549
5650 /// The "browser" field is provided by a module author as a hint to javascript bundlers or component tools when packaging modules for client side use.
5751 /// Multiple values are configured by [ResolveOptions::alias_fields].
5852 ///
5953 /// <https://github.com/defunctzombie/package-browser-field-spec>
60- #[ serde( skip) ]
6154 pub browser_fields : Vec < BrowserField > ,
6255}
6356
@@ -71,127 +64,85 @@ impl PackageJson {
7164 options : & ResolveOptions ,
7265 ) -> Result < Self , serde_json:: Error > {
7366 let mut raw_json: Value = serde_json:: from_str ( json) ?;
74- let mut data: BasePackageJson = serde_json:: from_value ( raw_json. clone ( ) ) ?;
75-
7667 let mut package_json = Self :: default ( ) ;
68+
7769 package_json. main_fields . reserve_exact ( options. main_fields . len ( ) ) ;
78- package_json. browser_fields . reserve_exact ( options. alias_fields . len ( ) ) ;
7970 package_json. exports . reserve_exact ( options. exports_fields . len ( ) ) ;
71+ package_json. browser_fields . reserve_exact ( options. alias_fields . len ( ) ) ;
8072
81- // Dynamically create `main_fields`.
82- for main_field_key in & options. main_fields {
83- match main_field_key. as_str ( ) {
84- "main" => {
85- if let Some ( main_field) = & data. main {
86- package_json. main_fields . push ( main_field. to_string_lossy ( ) . to_string ( ) ) ;
87- }
88- }
89- "module" => {
90- if let Some ( module_field) = & data. module {
91- package_json. main_fields . push ( module_field. to_string_lossy ( ) . to_string ( ) ) ;
92- }
93- }
94- "browser" => {
95- if let Some ( BrowserField :: String ( browser_field) ) = & data. browser {
96- package_json. main_fields . push ( browser_field. to_owned ( ) ) ;
97- }
98- }
99- field => {
100- // Using `get` + `clone` instead of remove here
101- // because `main_fields` may contain `browser`, which is also used in `browser_fields.
102- if let Some ( Value :: String ( value) ) = data. other_fields . get ( field) {
103- package_json. main_fields . push ( value. clone ( ) ) ;
104- }
105- }
106- } ;
107- }
108-
109- // Dynamically create `browser_fields`.
110- let dir = path. parent ( ) . unwrap ( ) ;
111- for object_path in & options. alias_fields {
112- let mut browser_field = if object_path. len ( ) == 1 && object_path[ 0 ] == "browser" {
113- if let Some ( field) = & data. browser {
114- field. to_owned ( )
115- } else {
116- continue ;
73+ if let Some ( json_object) = raw_json. as_object_mut ( ) {
74+ // Remove large fields that are useless for pragmatic use.
75+ json_object. remove ( "description" ) ;
76+ json_object. remove ( "keywords" ) ;
77+ json_object. remove ( "scripts" ) ;
78+ json_object. remove ( "dependencies" ) ;
79+ json_object. remove ( "devDependencies" ) ;
80+ json_object. remove ( "peerDependencies" ) ;
81+ json_object. remove ( "optionalDependencies" ) ;
82+
83+ // Add name.
84+ package_json. name =
85+ json_object. get ( "name" ) . and_then ( |field| field. as_str ( ) ) . map ( ToString :: to_string) ;
86+
87+ // Add imports.
88+ package_json. imports = json_object
89+ . get ( "imports" )
90+ . map ( ImportExportMap :: deserialize)
91+ . transpose ( ) ?
92+ . map ( Box :: new) ;
93+
94+ // Dynamically create `main_fields`.
95+ for main_field_key in & options. main_fields {
96+ // Using `get` + `clone` instead of remove here
97+ // because `main_fields` may contain `browser`, which is also used in `browser_fields.
98+ if let Some ( serde_json:: Value :: String ( value) ) = json_object. get ( main_field_key) {
99+ package_json. main_fields . push ( value. clone ( ) ) ;
117100 }
118- } else if let Some ( field) = Self :: get_value_by_path ( & data. other_fields , object_path) {
119- BrowserField :: deserialize ( field) ?
120- } else {
121- continue ;
122- } ;
101+ }
123102
124- // Normalize all relative paths to make browser_field a constant value lookup
125- if let BrowserField :: Map ( map) = & mut browser_field {
126- let keys = map. keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
127- for key in keys {
128- // Normalize the key if it looks like a file "foo.js"
129- if key. extension ( ) . is_some ( ) {
130- map. insert ( dir. normalize_with ( & key) , map[ & key] . clone ( ) ) ;
131- }
132- // Normalize the key if it is relative path "./relative"
133- if key. starts_with ( "." ) {
134- if let Some ( value) = map. remove ( & key) {
135- map. insert ( dir. normalize_with ( & key) , value) ;
103+ // Dynamically create `browser_fields`.
104+ let dir = path. parent ( ) . unwrap ( ) ;
105+ for object_path in & options. alias_fields {
106+ if let Some ( browser_field) = Self :: get_value_by_path ( json_object, object_path) {
107+ let mut browser_field = BrowserField :: deserialize ( browser_field) ?;
108+
109+ // Normalize all relative paths to make browser_field a constant value lookup
110+ if let BrowserField :: Map ( map) = & mut browser_field {
111+ let keys = map. keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
112+ for key in keys {
113+ // Normalize the key if it looks like a file "foo.js"
114+ if key. extension ( ) . is_some ( ) {
115+ map. insert ( dir. normalize_with ( & key) , map[ & key] . clone ( ) ) ;
116+ }
117+ // Normalize the key if it is relative path "./relative"
118+ if key. starts_with ( "." ) {
119+ if let Some ( value) = map. remove ( & key) {
120+ map. insert ( dir. normalize_with ( & key) , value) ;
121+ }
122+ }
136123 }
137124 }
125+ package_json. browser_fields . push ( browser_field) ;
138126 }
139127 }
140- package_json. browser_fields . push ( browser_field) ;
141- }
142128
143- // Dynamically create `exports`.
144- for object_path in & options. exports_fields {
145- if object_path . len ( ) == 1 && object_path[ 0 ] == "exports" {
146- if let Some ( exports) = & data . exports {
147- package_json. exports . push ( exports. to_owned ( ) ) ;
129+ // Dynamically create `exports`.
130+ for object_path in & options. exports_fields {
131+ if let Some ( exports ) = Self :: get_value_by_path ( json_object , object_path) {
132+ let exports = ImportExportField :: deserialize ( exports) ? ;
133+ package_json. exports . push ( exports) ;
148134 }
149- } else if let Some ( exports) = Self :: get_value_by_path ( & data. other_fields , object_path) {
150- package_json. exports . push ( ImportExportField :: deserialize ( exports) ?) ;
151135 }
152136 }
153137
154- // Bubble up `imports`
155- if let Some ( imports) = & data. imports {
156- package_json. imports = Box :: new ( imports. to_owned ( ) ) ;
157- }
158-
159138 package_json. path = path;
160139 package_json. realpath = realpath;
161-
162- // Remove large fields that are useless for pragmatic use
163- if options. remove_unused_fields {
164- data. scripts = None ;
165- data. dependencies = None ;
166- data. dependencies_meta = None ;
167- data. dev_dependencies = None ;
168- data. peer_dependencies = None ;
169- data. peer_dependencies_meta = None ;
170- data. bundle_dependencies = None ;
171- data. optional_dependencies = None ;
172- data. imports = None ;
173- data. exports = None ;
174- data. browser = None ;
175-
176- if let Some ( raw_json) = raw_json. as_object_mut ( ) {
177- raw_json. remove ( "description" ) ;
178- raw_json. remove ( "keywords" ) ;
179- raw_json. remove ( "scripts" ) ;
180- raw_json. remove ( "dependencies" ) ;
181- raw_json. remove ( "devDependencies" ) ;
182- raw_json. remove ( "peerDependencies" ) ;
183- raw_json. remove ( "optionalDependencies" ) ;
184- }
185- }
186-
187- package_json. data = data;
188140 package_json. raw_json = Arc :: new ( raw_json) ;
189-
190141 Ok ( package_json)
191142 }
192143
193144 fn get_value_by_path < ' a > (
194- fields : & ' a FxHashMap < String , serde_json:: Value > ,
145+ fields : & ' a serde_json :: Map < String , serde_json:: Value > ,
195146 path : & [ String ] ,
196147 ) -> Option < & ' a serde_json:: Value > {
197148 if path. is_empty ( ) {
0 commit comments