Skip to content

Commit e777918

Browse files
committed
remove npm2 dependency + fixes after reviews
1 parent 94c534d commit e777918

20 files changed

+366
-638
lines changed

lib/constants.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ export let TEST_RUNNER_NAME = "nativescript-unit-test-runner";
1616
export let LIVESYNC_EXCLUDED_FILE_PATTERNS = ["**/*.js.map", "**/*.ts"];
1717
export let XML_FILE_EXTENSION = ".xml";
1818

19+
export class PackageVersion {
20+
static NEXT = "next";
21+
static LATEST = "latest";
22+
}
23+
24+
export class SaveOptions {
25+
static PRODUCTION = "save";
26+
static DEV = "save-dev";
27+
static OPTIONAL = "save-optional";
28+
static EXACT = "save-exact";
29+
}
30+
1931
export class ReleaseType {
2032
static MAJOR = "major";
2133
static PREMAJOR = "premajor";
@@ -26,6 +38,14 @@ export class ReleaseType {
2638
static PRERELEASE = "prerelease";
2739
}
2840

41+
export let RESERVED_TEMPLATE_NAMES: IStringDictionary = {
42+
"default": "tns-template-hello-world",
43+
"tsc": "tns-template-hello-world-ts",
44+
"typescript": "tns-template-hello-world-ts",
45+
"ng": "tns-template-hello-world-ng",
46+
"angular": "tns-template-hello-world-ng"
47+
};
48+
2949
export class ITMSConstants {
3050
static ApplicationMetadataFile = "metadata.xml";
3151
static VerboseLoggingLevels = {
@@ -44,4 +64,4 @@ class ItunesConnectApplicationTypesClass implements IiTunesConnectApplicationTyp
4464
export let ItunesConnectApplicationTypes = new ItunesConnectApplicationTypesClass();
4565

4666
export let ANGULAR_NAME = "angular";
47-
export let TYPESCRIPT_NAME = "TypeScript";
67+
export let TYPESCRIPT_NAME = "typescript";

lib/declarations.ts

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,21 @@
11
interface INodePackageManager {
2-
getCache(): string;
3-
load(config?: any): IFuture<void>;
42
install(packageName: string, pathToSave: string, config?: any): IFuture<any>;
53
uninstall(packageName: string, config?: any, path?: string): IFuture<any>;
6-
cache(packageName: string, version: string, cache?: any): IFuture<IDependencyData>;
7-
cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void>;
8-
view(packageName: string, propertyName: string): IFuture<any>;
9-
executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture<any>;
10-
search(filter: string[], silent: boolean): IFuture<any>;
4+
view(packageName: string, config: any): IFuture<any>;
5+
search(filter: string[], config: any): IFuture<any>;
116
}
127

138
interface INpmInstallationManager {
14-
getCacheRootPath(): string;
15-
addToCache(packageName: string, version: string): IFuture<any>;
16-
cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void>;
17-
install(packageName: string, options?: INpmInstallOptions): IFuture<string>;
9+
install(packageName: string, packageDir: string, options?: INpmInstallOptions): IFuture<any>;
1810
getLatestVersion(packageName: string): IFuture<string>;
11+
getNextVersion(packageName: string): IFuture<string>;
1912
getLatestCompatibleVersion(packageName: string): IFuture<string>;
20-
getCachedPackagePath(packageName: string, version: string): string;
2113
}
2214

2315
interface INpmInstallOptions {
2416
pathToSave?: string;
2517
version?: string;
18+
dependencyType?: string;
2619
}
2720

2821
interface IDependencyData {
@@ -81,7 +74,7 @@ interface IOptions extends ICommonOptions {
8174
frameworkName: string;
8275
frameworkPath: string;
8376
frameworkVersion: string;
84-
ignoreScripts: boolean;
77+
ignoreScripts: boolean; //npm flag
8578
disableNpmInstall: boolean;
8679
ipa: string;
8780
keyStoreAlias: string;
@@ -95,7 +88,7 @@ interface IOptions extends ICommonOptions {
9588
bundle: boolean;
9689
platformTemplate: string;
9790
port: Number;
98-
production: boolean;
91+
production: boolean; //npm flag
9992
sdk: string;
10093
symlink: boolean;
10194
tnsModulesVersion: string;

lib/definitions/project.d.ts

+2-12
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,6 @@ interface IProjectDataService {
2626
* Describes working with templates.
2727
*/
2828
interface IProjectTemplatesService {
29-
/**
30-
* Defines the path where unpacked default template can be found.
31-
*/
32-
defaultTemplatePath: IFuture<string>;
33-
3429
/**
3530
* Prepares template for project creation.
3631
* In case templateName is not provided, use defaultTemplatePath.
@@ -39,7 +34,7 @@ interface IProjectTemplatesService {
3934
* @param {string} templateName The name of the template.
4035
* @return {string} Path to the directory where extracted template can be found.
4136
*/
42-
prepareTemplate(templateName: string): IFuture<string>;
37+
prepareTemplate(templateName: string, projectDir: string): IFuture<string>;
4338
}
4439

4540
interface IPlatformProjectServiceBase {
@@ -77,12 +72,7 @@ interface IPlatformProjectService {
7772
prepareProject(): IFuture<void>;
7873
prepareAppResources(appResourcesDirectoryPath: string): IFuture<void>;
7974
isPlatformPrepared(projectRoot: string): IFuture<boolean>;
80-
canUpdatePlatform(currentVersion: string, newVersion: string): IFuture<boolean>;
81-
/**
82-
* Provides a platform specific update logic for the specified runtime versions.
83-
* @return true in cases when the update procedure should continue.
84-
*/
85-
updatePlatform(currentVersion: string, newVersion: string, canUpdate: boolean, addPlatform?: Function, removePlatform?: (platforms: string[]) => IFuture<void>): IFuture<boolean>;
75+
canUpdatePlatform(newInstalledModuleDir: string): IFuture<boolean>;
8676
preparePluginNativeCode(pluginData: IPluginData, options?: any): IFuture<void>;
8777
removePluginNativeCode(pluginData: IPluginData): IFuture<void>;
8878
afterPrepareAllPlugins(): IFuture<void>;

lib/node-package-manager.ts

+70-97
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import Future = require("fibers/future");
2-
import * as npm from "npm";
1+
import * as path from "path";
32

43
interface INpmOpts {
54
config?: any;
@@ -8,35 +7,12 @@ interface INpmOpts {
87
}
98

109
export class NodePackageManager implements INodePackageManager {
11-
constructor(private $childProcess: IChildProcess,
10+
constructor(private $fs: IFileSystem,
11+
private $errors: IErrors,
12+
private $childProcess: IChildProcess,
1213
private $logger: ILogger,
1314
private $options: IOptions) { }
1415

15-
public getCache(): string {
16-
return npm.cache;
17-
}
18-
19-
public load(config?: any): IFuture<void> {
20-
if (npm.config.loaded) {
21-
let data = npm.config.sources.cli.data;
22-
Object.keys(data).forEach(k => delete data[k]);
23-
if (config) {
24-
_.assign(data, config);
25-
}
26-
return Future.fromResult();
27-
} else {
28-
let future = new Future<void>();
29-
npm.load(config, (err: Error) => {
30-
if (err) {
31-
future.throw(err);
32-
} else {
33-
future.return();
34-
}
35-
});
36-
return future;
37-
}
38-
}
39-
4016
public install(packageName: string, pathToSave: string, config?: any): IFuture<any> {
4117
return (() => {
4218
if (this.$options.disableNpmInstall) {
@@ -48,30 +24,54 @@ export class NodePackageManager implements INodePackageManager {
4824
}
4925

5026
try {
51-
return this.loadAndExecute("install", [pathToSave, packageName], { config: config }).wait();
27+
let jsonContentBefore = this.$fs.readJson(path.join(pathToSave, "package.json")).wait();
28+
let dependenciesBefore: Array<string> = [];
29+
if(jsonContentBefore && jsonContentBefore.dependencies) {
30+
for(let name in jsonContentBefore.dependencies) {
31+
dependenciesBefore.push(name);
32+
}
33+
}
34+
35+
let flags = this.getFlagsString(config, true);
36+
let params = ["install"];
37+
if(packageName !== pathToSave) {
38+
params.push(packageName); //because npm install ${pwd} on mac tries to install itself as a dependency (windows and linux have no such issues)
39+
}
40+
params = params.concat(flags);
41+
this.$childProcess.spawnFromEvent("npm", params, "close", { cwd: pathToSave }).wait();
42+
43+
let jsonContentAfter = this.$fs.readJson(path.join(pathToSave, "package.json")).wait();
44+
let dependenciesAfter: Array<string> = [];
45+
if(jsonContentAfter && jsonContentAfter.dependencies) {
46+
for(let name in jsonContentAfter.dependencies) {
47+
dependenciesAfter.push(name);
48+
}
49+
}
50+
51+
/** This diff is done in case the installed pakcage is a URL address, a path to local directory or a .tgz file
52+
* in these cases we don't have the package name and we can't rely on "npm install --json"" option
53+
* to get the project name because we have to parse the output from the stdout and we have no controll over it (so other messages may be mangled in stdout)
54+
* The solution is to compare package.json project dependencies before and after install and get the name of the installed package,
55+
* even if it's installed through local path or URL. If command installes more than one package, only the package originally installed is returned.
56+
*/
57+
let diff = _(jsonContentAfter.dependencies)
58+
.omitBy((val: string, key: string) => jsonContentBefore && jsonContentBefore.dependencies && jsonContentBefore.dependencies[key] && jsonContentBefore.dependencies[key] === val)
59+
.keys()
60+
.value();
61+
62+
if(diff.length <= 0 && dependenciesBefore.length === dependenciesAfter.length && packageName !== pathToSave) {
63+
this.$errors.failWithoutHelp(`The plugin ${packageName} is already installed`);
64+
}
65+
if(diff.length <= 0 && dependenciesBefore.length !== dependenciesAfter.length) {
66+
this.$errors.failWithoutHelp(`Couldn't install package correctly`);
67+
}
68+
69+
return diff;
5270
} catch (err) {
53-
if (err.code === "EPEERINVALID") {
71+
if (err.message && err.message.indexOf("EPEERINVALID") !== -1) {
5472
// Not installed peer dependencies are treated by npm 2 as errors, but npm 3 treats them as warnings.
5573
// We'll show them as warnings and let the user install them in case they are needed.
56-
// The strucutre of the error object in such case is:
57-
// { [Error: The package @angular/[email protected] does not satisfy its siblings' peerDependencies requirements!]
58-
// code: 'EPEERINVALID',
59-
// packageName: '@angular/core',
60-
// packageVersion: '2.1.0-beta.0',
61-
// peersDepending:
62-
// { '@angular/[email protected]': '2.1.0-beta.0',
63-
// '@angular/[email protected]': '2.1.0-beta.0',
64-
// '@angular/[email protected]': '2.1.0-beta.0',
65-
// '@angular/[email protected]': '2.1.0-beta.0',
66-
// '@angular/[email protected]': '2.1.0-beta.0',
67-
// '@angular/[email protected]': '2.1.0-beta.0',
68-
// '@angular/[email protected]': '2.1.0-beta.0',
69-
// '@angular/[email protected]': '2.1.0-beta.0',
70-
// '@ngrx/[email protected]': '^2.0.0',
71-
// '@ngrx/[email protected]': '^2.0.0',
72-
// '[email protected]': '~2.0.0' } }
7374
this.$logger.warn(err.message);
74-
this.$logger.trace("Required peerDependencies are: ", err.peersDepending);
7575
} else {
7676
// All other errors should be handled by the caller code.
7777
throw err;
@@ -81,66 +81,39 @@ export class NodePackageManager implements INodePackageManager {
8181
}
8282

8383
public uninstall(packageName: string, config?: any, path?: string): IFuture<any> {
84-
return this.loadAndExecute("uninstall", [[packageName]], { config, path });
85-
}
86-
87-
public search(filter: string[], silent: boolean): IFuture<any> {
88-
let args = (<any[]>([filter] || [])).concat(silent);
89-
return this.loadAndExecute("search", args);
90-
}
91-
92-
public cache(packageName: string, version: string, config?: any): IFuture<IDependencyData> {
93-
// function cache (pkg, ver, where, scrub, cb)
94-
return this.loadAndExecute("cache", [packageName, version, undefined, false], { subCommandName: "add", config: config });
95-
}
96-
97-
public cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void> {
98-
// function unpack (pkg, ver, unpackTarget, dMode, fMode, uid, gid, cb)
99-
return this.loadAndExecute("cache", [packageName, version, unpackTarget, null, null, null, null], { subCommandName: "unpack" });
84+
let flags = this.getFlagsString(config, false);
85+
return this.$childProcess.exec(`npm uninstall ${packageName} ${flags}`, { cwd: path });
10086
}
10187

102-
public view(packageName: string, propertyName: string): IFuture<any> {
103-
return this.loadAndExecute("view", [[packageName, propertyName], [false]]);
88+
public search(filter: string[], config: any): IFuture<any> {
89+
let args = (<any[]>([filter] || [])).concat(config.silent);
90+
return this.$childProcess.exec(`npm search ${args.join(" ")}`);
10491
}
10592

106-
public executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture<any> {
107-
return this.$childProcess.exec(npmCommandName, { cwd: currentWorkingDirectory });
108-
}
109-
110-
private loadAndExecute(commandName: string, args: any[], opts?: INpmOpts): IFuture<any> {
93+
public view(packageName: string, config: any): IFuture<any> {
11194
return (() => {
112-
opts = opts || {};
113-
this.load(opts.config).wait();
114-
return this.executeCore(commandName, args, opts).wait();
95+
let flags = this.getFlagsString(config, false);
96+
let viewResult = this.$childProcess.exec(`npm view ${packageName} ${flags}`).wait();
97+
return JSON.parse(viewResult);
11598
}).future<any>()();
11699
}
117100

118-
private executeCore(commandName: string, args: any[], opts?: INpmOpts): IFuture<any> {
119-
let future = new Future<any>();
120-
let oldNpmPath: string = undefined;
121-
let callback = (err: Error, data: any) => {
122-
if (oldNpmPath) {
123-
(<any>npm).prefix = oldNpmPath;
124-
}
125-
126-
if (err) {
127-
future.throw(err);
128-
} else {
129-
future.return(data);
101+
private getFlagsString(config: any, asArray: boolean) : any{
102+
let array:Array<string> = [];
103+
for(let flag in config) {
104+
if(config[flag]) {
105+
if(flag==="dist-tags" || flag==="versions") {
106+
array.push(` ${flag}`);
107+
continue;
108+
}
109+
array.push(`--${flag}`);
130110
}
131-
};
132-
args.push(callback);
133-
134-
if (opts && opts.path) {
135-
oldNpmPath = npm.prefix;
136-
(<any>npm).prefix = opts.path;
111+
}
112+
if(asArray) {
113+
return array;
137114
}
138115

139-
let subCommandName: string = opts.subCommandName;
140-
let command = subCommandName ? npm.commands[commandName][subCommandName] : npm.commands[commandName];
141-
command.apply(this, args);
142-
143-
return future;
116+
return array.join(" ");
144117
}
145118
}
146119
$injector.register("npm", NodePackageManager);

0 commit comments

Comments
 (0)