@@ -3,9 +3,9 @@ import * as fs from "fs";
3
3
import * as path from "path" ;
4
4
import * as shelljs from "shelljs" ;
5
5
import Future = require( "fibers/future" ) ;
6
- import { NpmDependencyResolver , TnsModulesCopy , NpmPluginPrepare } from "./node-modules-dest-copy" ;
6
+ import { TnsModulesCopy , NpmPluginPrepare } from "./node-modules-dest-copy" ;
7
7
import * as fiberBootstrap from "../../common/fiber-bootstrap" ;
8
- import { sleep } from "../../../lib/common/helpers" ;
8
+ import { sleep } from "../../../lib/common/helpers" ;
9
9
10
10
let glob = require ( "glob" ) ;
11
11
@@ -37,7 +37,7 @@ export class NodeModulesBuilder implements INodeModulesBuilder {
37
37
} , ( er : Error , files : string [ ] ) => {
38
38
fiberBootstrap . run ( ( ) => {
39
39
40
- while ( this . $lockfile . check ( ) . wait ( ) ) {
40
+ while ( this . $lockfile . check ( ) . wait ( ) ) {
41
41
sleep ( 10 ) ;
42
42
}
43
43
@@ -85,7 +85,7 @@ export class NodeModulesBuilder implements INodeModulesBuilder {
85
85
let intervalId = setInterval ( ( ) => {
86
86
fiberBootstrap . run ( ( ) => {
87
87
if ( ! this . $lockfile . check ( ) . wait ( ) || future . isResolved ( ) ) {
88
- if ( ! future . isResolved ( ) ) {
88
+ if ( ! future . isResolved ( ) ) {
89
89
future . return ( ) ;
90
90
}
91
91
clearInterval ( intervalId ) ;
@@ -133,57 +133,165 @@ export class NodeModulesBuilder implements INodeModulesBuilder {
133
133
// Force copying if the destination doesn't exist.
134
134
lastModifiedTime = null ;
135
135
}
136
-
137
- //TODO: plamen5kov: WIP
138
- let depJsonStr = this . $childProcess . exec ( "npm list --prod --json" ) . wait ( ) ;
139
- let prodDependenciesJson = JSON . parse ( depJsonStr ) ;
140
- let productionDepArray = this . getProductionDependencyNames ( prodDependenciesJson ) ;
141
136
137
+ let productionDependencies = this . getProductionDependencies ( this . $projectData . projectDir ) ;
142
138
143
- let nodeModules = this . getChangedNodeModules ( absoluteOutputPath , platform , lastModifiedTime ) . wait ( ) ;
139
+ // console.log(productionDependencies );
144
140
145
- const resolver = new NpmDependencyResolver ( this . $projectData . projectDir ) ;
146
- const resolvedDependencies = resolver . resolveDependencies ( _ . keys ( nodeModules ) , platform ) ;
141
+ // TODO: Pip3r4o - result is not used currently
142
+ // let nodeModules = this.getChangedNodeModules(absoluteOutputPath , platform, lastModifiedTime).wait( );
147
143
148
144
if ( ! this . $options . bundle ) {
149
145
const tnsModulesCopy = this . $injector . resolve ( TnsModulesCopy , {
150
146
outputRoot : absoluteOutputPath
151
147
} ) ;
152
- tnsModulesCopy . copyModules ( resolvedDependencies , platform ) ;
148
+ tnsModulesCopy . copyModules ( productionDependencies , platform ) ;
153
149
} else {
154
150
this . cleanNodeModules ( absoluteOutputPath , platform ) ;
155
151
}
156
152
157
153
const npmPluginPrepare = this . $injector . resolve ( NpmPluginPrepare , { } ) ;
158
- npmPluginPrepare . preparePlugins ( resolvedDependencies , platform ) ;
154
+ npmPluginPrepare . preparePlugins ( productionDependencies , platform ) ;
159
155
} ) . future < void > ( ) ( ) ;
160
156
}
161
157
162
- private getProductionDependencyNames ( inputJson : any ) : any {
163
- var finalDependencies : any = { } ;
164
- var queue : any = [ ] ;
158
+ public getProductionDependencies ( projectPath : string ) {
159
+ var deps : any = [ ] ;
160
+ var seen : any = { } ;
165
161
166
- inputJson . level = 0 ;
167
- queue . push ( inputJson )
162
+ var pJson = path . join ( projectPath , "package.json" ) ;
163
+ var nodeModulesDir = path . join ( projectPath , "node_modules" ) ;
168
164
169
- while ( queue . length > 0 ) {
170
- var parent = queue . pop ( ) ;
165
+ var content = require ( pJson ) ;
171
166
172
- if ( parent . dependencies ) {
173
- for ( var dep in parent . dependencies ) {
174
- var currentDependency = parent . dependencies [ dep ] ;
175
- currentDependency . level = parent . level + 1 ;
176
- queue . push ( currentDependency ) ;
177
- finalDependencies [ dep ] = currentDependency ;
167
+ Object . keys ( content . dependencies ) . forEach ( ( key ) => {
168
+ var depth = 0 ;
169
+ var directory = path . join ( nodeModulesDir , key ) ;
170
+
171
+ // find and traverse child with name `key`, parent's directory -> dep.directory
172
+ traverseChild ( key , directory , depth ) ;
173
+ } ) ;
174
+
175
+ return filterUniqueDirectories ( deps ) ;
176
+
177
+ function traverseChild ( name : string , currentModulePath : string , depth : number ) {
178
+ // check if key appears in a scoped module dependency
179
+ var isScoped = name . indexOf ( '@' ) === 0 ;
180
+
181
+ if ( ! isScoped ) {
182
+ // Check if child has been extracted in the parent's node modules, AND THEN in `node_modules`
183
+ // Slower, but prevents copying wrong versions if multiple of the same module are installed
184
+ // Will also prevent copying project's devDependency's version if current module depends on another version
185
+ var modulePath = path . join ( currentModulePath , "node_modules" , name ) ; // /node_modules/parent/node_modules/<package>
186
+ var exists = ensureModuleExists ( modulePath ) ;
187
+
188
+ if ( exists ) {
189
+ var dep = addDependency ( deps , name , modulePath , depth + 1 ) ;
190
+
191
+ traverseModule ( modulePath , depth + 1 , dep ) ;
192
+ } else {
193
+ modulePath = path . join ( nodeModulesDir , name ) ; // /node_modules/<package>
194
+ exists = ensureModuleExists ( modulePath ) ;
195
+
196
+ if ( ! exists ) {
197
+ return ;
198
+ }
199
+
200
+ var dep = addDependency ( deps , name , modulePath , 0 ) ;
201
+
202
+ traverseModule ( modulePath , 0 , dep ) ;
203
+ }
204
+
205
+ }
206
+ // module is scoped
207
+ else {
208
+ var scopeSeparatorIndex = name . indexOf ( '/' ) ;
209
+ var scope = name . substring ( 0 , scopeSeparatorIndex ) ;
210
+ var moduleName = name . substring ( scopeSeparatorIndex + 1 , name . length ) ;
211
+ var scopedModulePath = path . join ( nodeModulesDir , scope , moduleName ) ;
212
+
213
+ var exists = ensureModuleExists ( scopedModulePath ) ;
214
+
215
+ if ( exists ) {
216
+ var dep = addDependency ( deps , name , scopedModulePath , 0 ) ;
217
+ traverseModule ( scopedModulePath , depth , dep ) ;
218
+ }
219
+ else {
220
+ scopedModulePath = path . join ( currentModulePath , "node_modules" , scope , moduleName ) ;
221
+
222
+ exists = ensureModuleExists ( scopedModulePath ) ;
223
+
224
+ if ( ! exists ) {
225
+ return ;
226
+ }
227
+
228
+ var dep = addDependency ( deps , name , scopedModulePath , depth + 1 ) ;
229
+ traverseModule ( scopedModulePath , depth + 1 , dep ) ;
230
+ }
231
+ }
232
+
233
+ function traverseModule ( modulePath : string , depth : number , currentDependency : any ) {
234
+ var packageJsonPath = path . join ( modulePath , 'package.json' ) ;
235
+ var packageJsonExists = fs . lstatSync ( packageJsonPath ) . isFile ( ) ;
236
+
237
+ if ( packageJsonExists ) {
238
+ var packageJsonContents = require ( packageJsonPath ) ;
239
+
240
+ if ( ! ! packageJsonContents . nativescript ) {
241
+ // add `nativescript` property, necessary for resolving plugins
242
+ currentDependency . nativescript = packageJsonContents . nativescript ;
243
+ }
244
+
245
+ if ( packageJsonContents . dependencies ) {
246
+ Object . keys ( packageJsonContents . dependencies ) . forEach ( ( key ) => {
247
+
248
+ traverseChild ( key , modulePath , depth ) ;
249
+ } ) ;
250
+ }
251
+ }
252
+ }
253
+
254
+ function addDependency ( deps : any [ ] , name : string , directory : string , depth : number ) {
255
+ var dep : any = { } ;
256
+ dep . name = name ;
257
+ dep . directory = directory ;
258
+ dep . depth = depth ;
259
+
260
+ deps . push ( dep ) ;
261
+
262
+ return dep ;
263
+ }
264
+
265
+ function ensureModuleExists ( modulePath : string ) : boolean {
266
+ try {
267
+ var exists = fs . lstatSync ( modulePath ) ;
268
+ return exists . isDirectory ( ) ;
269
+ } catch ( e ) {
270
+ return false ;
178
271
}
179
272
}
180
273
}
181
274
182
- return finalDependencies ;
275
+ function filterUniqueDirectories ( dependencies : any ) {
276
+ var unique : any = [ ] ;
277
+ var distinct : any = [ ] ;
278
+ for ( var i in dependencies ) {
279
+ var dep = dependencies [ i ] ;
280
+ if ( distinct . indexOf ( dep . directory ) > - 1 ) {
281
+ continue ;
282
+ }
283
+
284
+ distinct . push ( dep . directory ) ;
285
+ unique . push ( dep ) ;
286
+ }
287
+
288
+ return unique ;
289
+ }
183
290
}
184
291
185
292
public cleanNodeModules ( absoluteOutputPath : string , platform : string ) : void {
186
293
shelljs . rm ( "-rf" , absoluteOutputPath ) ;
187
- }
294
+ }
188
295
}
296
+
189
297
$injector . register ( "nodeModulesBuilder" , NodeModulesBuilder ) ;
0 commit comments