@@ -2,12 +2,16 @@ use crate::emitter::EmitterFactory;
2
2
use crate :: graph_util:: { create_eszip_from_graph_raw, create_graph} ;
3
3
use deno_ast:: MediaType ;
4
4
use deno_core:: error:: AnyError ;
5
+ use deno_core:: futures:: io:: { AllowStdIo , BufReader } ;
5
6
use deno_core:: { serde_json, FastString , JsBuffer , ModuleSpecifier } ;
6
7
use deno_fs:: { FileSystem , RealFs } ;
7
8
use deno_npm:: NpmSystemInfo ;
8
9
use eszip:: { EszipV2 , ModuleKind } ;
9
10
use sb_fs:: { build_vfs, VfsOpts } ;
10
- use std:: path:: PathBuf ;
11
+ use std:: fs;
12
+ use std:: fs:: { create_dir_all, File } ;
13
+ use std:: io:: Write ;
14
+ use std:: path:: { Path , PathBuf } ;
11
15
use std:: sync:: Arc ;
12
16
13
17
pub mod emitter;
@@ -25,6 +29,26 @@ pub enum EszipPayloadKind {
25
29
Eszip ( EszipV2 ) ,
26
30
}
27
31
32
+ pub async fn payload_to_eszip ( eszip_payload_kind : EszipPayloadKind ) -> EszipV2 {
33
+ match eszip_payload_kind {
34
+ EszipPayloadKind :: Eszip ( data) => data,
35
+ _ => {
36
+ let bytes = match eszip_payload_kind {
37
+ EszipPayloadKind :: JsBufferKind ( js_buffer) => Vec :: from ( & * js_buffer) ,
38
+ EszipPayloadKind :: VecKind ( vec) => vec,
39
+ _ => panic ! ( "It should not get here" ) ,
40
+ } ;
41
+
42
+ let bufreader = BufReader :: new ( AllowStdIo :: new ( bytes. as_slice ( ) ) ) ;
43
+ let ( eszip, loader) = eszip:: EszipV2 :: parse ( bufreader) . await . unwrap ( ) ;
44
+
45
+ loader. await . unwrap ( ) ;
46
+
47
+ eszip
48
+ }
49
+ }
50
+ }
51
+
28
52
pub async fn generate_binary_eszip (
29
53
file : PathBuf ,
30
54
emitter_factory : Arc < EmitterFactory > ,
@@ -95,3 +119,116 @@ pub async fn generate_binary_eszip(
95
119
eszip
96
120
}
97
121
}
122
+
123
+ fn extract_file_specifiers ( eszip : & EszipV2 ) -> Vec < String > {
124
+ eszip
125
+ . specifiers ( )
126
+ . iter ( )
127
+ . filter ( |specifier| specifier. starts_with ( "file:" ) )
128
+ . cloned ( )
129
+ . collect ( )
130
+ }
131
+
132
+ pub struct ExtractEszipPayload {
133
+ pub data : EszipPayloadKind ,
134
+ pub folder : PathBuf ,
135
+ }
136
+
137
+ fn create_module_path (
138
+ global_specifier : & str ,
139
+ entry_path : & Path ,
140
+ output_folder : & Path ,
141
+ ) -> PathBuf {
142
+ let cleaned_specifier = global_specifier. replace ( entry_path. to_str ( ) . unwrap ( ) , "" ) ;
143
+ let module_path = PathBuf :: from ( cleaned_specifier) ;
144
+
145
+ if let Some ( parent) = module_path. parent ( ) {
146
+ if parent. parent ( ) . is_some ( ) {
147
+ let output_folder_and_mod_folder =
148
+ output_folder. join ( parent. strip_prefix ( "/" ) . unwrap ( ) ) ;
149
+ if !output_folder_and_mod_folder. exists ( ) {
150
+ create_dir_all ( & output_folder_and_mod_folder) . unwrap ( ) ;
151
+ }
152
+ }
153
+ }
154
+
155
+ output_folder. join ( module_path. strip_prefix ( "/" ) . unwrap ( ) )
156
+ }
157
+
158
+ async fn extract_modules (
159
+ eszip : & EszipV2 ,
160
+ specifiers : & [ String ] ,
161
+ lowest_path : & str ,
162
+ output_folder : & Path ,
163
+ ) {
164
+ let main_path = PathBuf :: from ( lowest_path) ;
165
+ let entry_path = main_path. parent ( ) . unwrap ( ) ;
166
+ for global_specifier in specifiers {
167
+ let module_path = create_module_path ( global_specifier, entry_path, output_folder) ;
168
+ let module_content = eszip
169
+ . get_module ( global_specifier)
170
+ . unwrap ( )
171
+ . take_source ( )
172
+ . await
173
+ . unwrap ( ) ;
174
+
175
+ let mut file = File :: create ( & module_path) . unwrap ( ) ;
176
+ file. write_all ( module_content. as_ref ( ) ) . unwrap ( ) ;
177
+ }
178
+ }
179
+
180
+ pub async fn extract_eszip ( payload : ExtractEszipPayload ) {
181
+ let eszip = payload_to_eszip ( payload. data ) . await ;
182
+ let output_folder = payload. folder ;
183
+
184
+ if !output_folder. exists ( ) {
185
+ create_dir_all ( & output_folder) . unwrap ( ) ;
186
+ }
187
+
188
+ let file_specifiers = extract_file_specifiers ( & eszip) ;
189
+ if let Some ( lowest_path) = sb_core:: util:: path:: find_lowest_path ( & file_specifiers) {
190
+ extract_modules ( & eszip, & file_specifiers, & lowest_path, & output_folder) . await ;
191
+ } else {
192
+ panic ! ( "Path seems to be invalid" ) ;
193
+ }
194
+ }
195
+
196
+ pub async fn extract_from_file ( eszip_file : PathBuf , output_path : PathBuf ) {
197
+ let eszip_content = fs:: read ( eszip_file) . expect ( "File does not exist" ) ;
198
+ extract_eszip ( ExtractEszipPayload {
199
+ data : EszipPayloadKind :: VecKind ( eszip_content) ,
200
+ folder : output_path,
201
+ } )
202
+ . await ;
203
+ }
204
+
205
+ #[ cfg( test) ]
206
+ mod test {
207
+ use crate :: {
208
+ extract_eszip, generate_binary_eszip, EmitterFactory , EszipPayloadKind , ExtractEszipPayload ,
209
+ } ;
210
+ use std:: fs:: remove_dir_all;
211
+ use std:: path:: PathBuf ;
212
+ use std:: sync:: Arc ;
213
+
214
+ #[ tokio:: test]
215
+ #[ allow( clippy:: arc_with_non_send_sync) ]
216
+ async fn test_module_code_no_eszip ( ) {
217
+ let eszip = generate_binary_eszip (
218
+ PathBuf :: from ( "../base/test_cases/npm/index.ts" ) ,
219
+ Arc :: new ( EmitterFactory :: new ( ) ) ,
220
+ None ,
221
+ None ,
222
+ )
223
+ . await ;
224
+ let eszip = eszip. unwrap ( ) ;
225
+ extract_eszip ( ExtractEszipPayload {
226
+ data : EszipPayloadKind :: Eszip ( eszip) ,
227
+ folder : PathBuf :: from ( "../base/test_cases/extracted-npm/" ) ,
228
+ } )
229
+ . await ;
230
+
231
+ assert ! ( PathBuf :: from( "../base/test_cases/extracted-npm/hello.js" ) . exists( ) ) ;
232
+ remove_dir_all ( PathBuf :: from ( "../base/test_cases/extracted-npm/" ) ) . unwrap ( ) ;
233
+ }
234
+ }
0 commit comments