Skip to content

Commit 7b10417

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

File tree

5 files changed

+147
-178
lines changed

5 files changed

+147
-178
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,112 @@
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 child has been extracted in the parent's node modules, AND THEN in `node_modules`
35+
// Slower, but prevents copying wrong versions if multiple of the same module are installed
36+
// Will also prevent copying project's devDependency's version if current module depends on another version
37+
let modulePath = path.join(currentModulePath, "node_modules", name); // node_modules/parent/node_modules/<package>
38+
let alternativeModulePath = path.join(this.rootNodeModulesPath, name);
39+
40+
this.findModule(modulePath, alternativeModulePath, name, depth);
41+
}
42+
43+
private findModule(modulePath: string, alternativeModulePath: string, name: string, depth: number) {
44+
let exists = this.moduleExists(modulePath);
45+
46+
if (exists) {
47+
if (this.seen[modulePath]) {
48+
return;
49+
}
50+
51+
let dependency = this.addDependency(name, modulePath, depth + 1);
52+
this.readModuleDependencies(modulePath, depth + 1, dependency);
53+
} else {
54+
modulePath = alternativeModulePath; // /node_modules/<package>
55+
exists = this.moduleExists(modulePath);
56+
57+
if (!exists) {
58+
return;
59+
}
60+
61+
if (this.seen[modulePath]) {
62+
return;
63+
}
64+
65+
let dependency = this.addDependency(name, modulePath, 0);
66+
this.readModuleDependencies(modulePath, 0, dependency);
67+
}
68+
69+
this.seen[modulePath] = true;
70+
}
71+
72+
private readModuleDependencies(modulePath: string, depth: number, currentModule: any): void {
73+
let packageJsonPath = path.join(modulePath, 'package.json');
74+
let packageJsonExists = fs.lstatSync(packageJsonPath).isFile();
75+
76+
if (packageJsonExists) {
77+
let packageJsonContents = this.$fs.readJson(packageJsonPath).wait();
78+
79+
if (!!packageJsonContents.nativescript) {
80+
// add `nativescript` property, necessary for resolving plugins
81+
currentModule.nativescript = packageJsonContents.nativescript;
82+
}
83+
84+
_.keys(packageJsonContents.dependencies).forEach((dependencyName) => {
85+
this.traverseDependency(dependencyName, modulePath, depth);
86+
});
87+
}
88+
}
89+
90+
private addDependency(name: string, directory: string, depth: number): any {
91+
let dependency: any = {
92+
name,
93+
directory,
94+
depth
95+
};
96+
97+
this.resolvedDependencies.push(dependency);
98+
99+
return dependency;
100+
}
101+
102+
private moduleExists(modulePath: string): boolean {
103+
try {
104+
let exists = fs.lstatSync(modulePath);
105+
return exists.isDirectory();
106+
} catch (e) {
107+
return false;
108+
}
109+
}
110+
}
111+
112+
$injector.register("nodeModulesDependenciesBuilder", NodeModulesDependenciesBuilder);

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

+3-8
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

@@ -30,13 +28,11 @@ export class TnsModulesCopy {
3028
let allFiles = this.$fs.enumerateFilesInDirectorySync(tnsCoreModulesResourcePath);
3129
let deleteFilesFutures = allFiles.filter(file => minimatch(file, "**/*.ts", { nocase: true })).map(file => this.$fs.deleteFile(file));
3230
Future.wait(deleteFilesFutures);
33-
34-
shelljs.rm("-rf", path.join(this.outputRoot, dependency.name, "node_modules"));
3531
}
3632
}
3733
}
3834

39-
private copyDependencyDir(dependency: any) {
35+
private copyDependencyDir(dependency: any): void {
4036
if (dependency.depth === 0) {
4137
let isScoped = dependency.name.indexOf("@") === 0;
4238
let targetDir = this.outputRoot;
@@ -47,7 +43,6 @@ export class TnsModulesCopy {
4743

4844
shelljs.mkdir("-p", targetDir);
4945
shelljs.cp("-Rf", dependency.directory, targetDir);
50-
// console.log("Copied dependency: " + dependency.name);
5146
}
5247
}
5348
}

0 commit comments

Comments
 (0)