Skip to content

Commit 1b80824

Browse files
committed
separate logic for determining production dependencies in a class
fix broken tests
1 parent 77f86a3 commit 1b80824

File tree

5 files changed

+160
-176
lines changed

5 files changed

+160
-176
lines changed

lib/definitions/platform.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,7 @@ interface INodeModulesBuilder {
5656
prepareNodeModules(absoluteOutputPath: string, platform: string, lastModifiedTime: Date): IFuture<void>;
5757
cleanNodeModules(absoluteOutputPath: string, platform: string): void;
5858
}
59+
60+
interface INodeModulesDependenciesBuilder {
61+
getProductionDependencies(projectPath: string): void;
62+
}

lib/tools/node-modules/node-modules-builder.ts

+3-140
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as path from "path";
44
import * as shelljs from "shelljs";
55
import Future = require("fibers/future");
66
import { TnsModulesCopy, NpmPluginPrepare } from "./node-modules-dest-copy";
7+
import { NodeModulesDependenciesBuilder } from "./node-modules-dependencies-builder";
78
import * as fiberBootstrap from "../../common/fiber-bootstrap";
89
import { sleep } from "../../../lib/common/helpers";
910

@@ -134,12 +135,8 @@ export class NodeModulesBuilder implements INodeModulesBuilder {
134135
lastModifiedTime = null;
135136
}
136137

137-
let productionDependencies = this.getProductionDependencies(this.$projectData.projectDir);
138-
139-
// console.log(productionDependencies);
140-
141-
// TODO: Pip3r4o - result is not used currently
142-
// let nodeModules = this.getChangedNodeModules(absoluteOutputPath, platform, lastModifiedTime).wait();
138+
let dependenciesBuilder = this.$injector.resolve(NodeModulesDependenciesBuilder, {});
139+
let productionDependencies = dependenciesBuilder.getProductionDependencies(this.$projectData.projectDir);
143140

144141
if (!this.$options.bundle) {
145142
const tnsModulesCopy = this.$injector.resolve(TnsModulesCopy, {
@@ -155,140 +152,6 @@ export class NodeModulesBuilder implements INodeModulesBuilder {
155152
}).future<void>()();
156153
}
157154

158-
public getProductionDependencies(projectPath: string) {
159-
var deps: any = [];
160-
var seen: any = {};
161-
162-
var pJson = path.join(projectPath, "package.json");
163-
var nodeModulesDir = path.join(projectPath, "node_modules");
164-
165-
var content = require(pJson);
166-
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;
271-
}
272-
}
273-
}
274-
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-
}
290-
}
291-
292155
public cleanNodeModules(absoluteOutputPath: string, platform: string): void {
293156
shelljs.rm("-rf", absoluteOutputPath);
294157
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import * as path from "path";
2+
import * as fs from "fs";
3+
4+
export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesBuilder {
5+
private projectPath: string;
6+
private rootNodeModulesPath: string;
7+
private resolvedDependencies: any[];
8+
private seen: any;
9+
10+
public constructor(private $fs: IFileSystem) {
11+
this.seen = {};
12+
this.resolvedDependencies = [];
13+
}
14+
15+
public getProductionDependencies(projectPath: string): any {
16+
this.projectPath = projectPath;
17+
this.rootNodeModulesPath = path.join(this.projectPath, "node_modules");
18+
19+
let projectPackageJsonpath = path.join(this.projectPath, "package.json");
20+
let packageJsonContent = this.$fs.readJson(projectPackageJsonpath).wait();
21+
22+
_.keys(packageJsonContent.dependencies).forEach(dependencyName => {
23+
let depth = 0;
24+
let directory = path.join(this.rootNodeModulesPath, dependencyName);
25+
26+
// find and traverse child with name `key`, parent's directory -> dep.directory
27+
this.traverseDependency(dependencyName, directory, depth);
28+
});
29+
30+
return this.resolvedDependencies;
31+
}
32+
33+
private traverseDependency(name: string, currentModulePath: string, depth: number): void {
34+
// check if key appears in a scoped module dependency
35+
let isScoped = name.indexOf('@') === 0;
36+
37+
if (!isScoped) {
38+
// Check if child has been extracted in the parent's node modules, AND THEN in `node_modules`
39+
// Slower, but prevents copying wrong versions if multiple of the same module are installed
40+
// Will also prevent copying project's devDependency's version if current module depends on another version
41+
let modulePath = path.join(currentModulePath, "node_modules", name); // node_modules/parent/node_modules/<package>
42+
let alternativeModulePath = path.join(this.rootNodeModulesPath, name);
43+
44+
this.findModule(modulePath, alternativeModulePath, name, depth);
45+
} else { // module is scoped
46+
let scopeSeparatorIndex = name.indexOf('/');
47+
let scope = name.substring(0, scopeSeparatorIndex);
48+
let moduleName = name.substring(scopeSeparatorIndex + 1, name.length);
49+
let scopedModulePath = path.join(currentModulePath, "node_modules", scope, moduleName);
50+
let alternativeScopedModulePath = path.join(this.rootNodeModulesPath, scope, moduleName);
51+
52+
this.findModule(scopedModulePath, alternativeScopedModulePath, name, depth);
53+
}
54+
}
55+
56+
private findModule(modulePath: string, alternativeModulePath: string, name: string, depth: number) {
57+
let exists = this.moduleExists(modulePath);
58+
59+
if (exists) {
60+
if (this.seen[modulePath]) {
61+
return;
62+
}
63+
64+
let dependency = this.addDependency(name, modulePath, depth + 1);
65+
this.readModuleDependencies(modulePath, depth + 1, dependency);
66+
} else {
67+
modulePath = alternativeModulePath; // /node_modules/<package>
68+
exists = this.moduleExists(modulePath);
69+
70+
if (!exists) {
71+
return;
72+
}
73+
74+
if (this.seen[modulePath]) {
75+
return;
76+
}
77+
78+
let dependency = this.addDependency(name, modulePath, 0);
79+
this.readModuleDependencies(modulePath, 0, dependency);
80+
}
81+
82+
this.seen[modulePath] = true;
83+
}
84+
85+
private readModuleDependencies(modulePath: string, depth: number, currentModule: any): void {
86+
let packageJsonPath = path.join(modulePath, 'package.json');
87+
let packageJsonExists = fs.lstatSync(packageJsonPath).isFile();
88+
89+
if (packageJsonExists) {
90+
let packageJsonContents = this.$fs.readJson(packageJsonPath).wait();
91+
92+
if (!!packageJsonContents.nativescript) {
93+
// add `nativescript` property, necessary for resolving plugins
94+
currentModule.nativescript = packageJsonContents.nativescript;
95+
}
96+
97+
_.keys(packageJsonContents.dependencies).forEach((dependencyName) => {
98+
this.traverseDependency(dependencyName, modulePath, depth);
99+
});
100+
}
101+
}
102+
103+
private addDependency(name: string, directory: string, depth: number): any {
104+
let dependency: any = {
105+
name,
106+
directory,
107+
depth
108+
};
109+
110+
this.resolvedDependencies.push(dependency);
111+
112+
return dependency;
113+
}
114+
115+
private moduleExists(modulePath: string): boolean {
116+
try {
117+
let exists = fs.lstatSync(modulePath);
118+
return exists.isDirectory();
119+
} catch (e) {
120+
return false;
121+
}
122+
}
123+
}
124+
125+
$injector.register("nodeModulesDependenciesBuilder", NodeModulesDependenciesBuilder);

lib/tools/node-modules/node-modules-dest-copy.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import * as fs from "fs";
21
import * as path from "path";
3-
import * as semver from "semver";
42
import * as shelljs from "shelljs";
53
import * as constants from "../../constants";
64
import * as minimatch from "minimatch";
@@ -18,8 +16,8 @@ export class TnsModulesCopy {
1816
}
1917

2018
public copyModules(dependencies: any[], platform: string): void {
21-
for (var entry in dependencies) {
22-
var dependency = dependencies[entry];
19+
for (let entry in dependencies) {
20+
let dependency = dependencies[entry];
2321

2422
this.copyDependencyDir(dependency);
2523

@@ -36,7 +34,7 @@ export class TnsModulesCopy {
3634
}
3735
}
3836

39-
private copyDependencyDir(dependency: any) {
37+
private copyDependencyDir(dependency: any): void {
4038
if (dependency.depth === 0) {
4139
let isScoped = dependency.name.indexOf("@") === 0;
4240
let targetDir = this.outputRoot;
@@ -47,7 +45,6 @@ export class TnsModulesCopy {
4745

4846
shelljs.mkdir("-p", targetDir);
4947
shelljs.cp("-Rf", dependency.directory, targetDir);
50-
// console.log("Copied dependency: " + dependency.name);
5148
}
5249
}
5350
}

0 commit comments

Comments
 (0)