Skip to content

Commit 0eb71b6

Browse files
committed
Merge branch 'release' into 'master'
2 parents 1937f29 + 1afcdc3 commit 0eb71b6

33 files changed

+975
-600
lines changed

CHANGELOG.md

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
NativeScript CLI Changelog
22
================
33

4+
5.0.1 (2018, November 14)
5+
==
6+
### Implemented
7+
* [Implemented #4083](https://github.com/NativeScript/nativescript-cli/pull/4083): API: Add public API for deviceFound and deviceLost for preview devices
8+
* [Implemented #4087](https://github.com/NativeScript/nativescript-cli/pull/4087): API: Expose public method for getting the qr code of playground app
9+
* [Implemented #4093](https://github.com/NativeScript/nativescript-cli/pull/4093): API: Expose public api for starting the livesync operation to preview app
10+
11+
### Fixed
12+
* [Fixed #2670](https://github.com/NativeScript/nativescript-cli/issues/2670): Command line `tns run android --clean` rebuilds
13+
* [Fixed #4043](https://github.com/NativeScript/nativescript-cli/issues/4043): `tns preview` fails when local plugin is referenced with tag in `package.json`
14+
* [Fixed #4046](https://github.com/NativeScript/nativescript-cli/issues/4046):`tns debug ios` does not work with bigger projects on slower devices
15+
* [Fixed #4055](https://github.com/NativeScript/nativescript-cli/pull/4055): API: Remove persisted emulator's data on deviceLost event
16+
* [Fixed #4056](https://github.com/NativeScript/nativescript-cli/pull/4056): API: `TypeError: Invalid Version: null` is thrown when emulator is stopped immediately after start
17+
* [Fixed #4071](https://github.com/NativeScript/nativescript-cli/issues/4071): Unable to run `tns test <platform>`
18+
* [Fixed #4073](https://github.com/NativeScript/nativescript-cli/pull/4073): Error is thrown when Node.js 11 is used
19+
* [Fixed #4076](https://github.com/NativeScript/nativescript-cli/issues/4076): Cannot connect to device socket when run debug with justlaunch
20+
* [Fixed #4079](https://github.com/NativeScript/nativescript-cli/pull/4079): API: Reset errors when fallback to list avds from director
21+
* [Fixed #4090](https://github.com/NativeScript/nativescript-cli/issues/4090): `tns preview` and `tns platform add ...` issue
22+
* [Fixed #4096](https://github.com/NativeScript/nativescript-cli/issues/4096): NativeScript v4 is not using the v4 of the app templates during project creation
23+
* [Fixed #4100](https://github.com/NativeScript/nativescript-cli/issues/4100): Apply `before-plugins.gradle` file in the plugin `build.gradle`
24+
25+
426
5.0.0 (2018, November 1)
527
==
628

lib/base-package-manager.ts

+61-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,62 @@
11
import { isInteractive } from "./common/helpers";
22

3-
export class BasePackageManager {
3+
export abstract class BasePackageManager implements INodePackageManager {
4+
public abstract install(packageName: string, pathToSave: string, config: INodePackageManagerInstallOptions): Promise<INpmInstallResultInfo>;
5+
public abstract uninstall(packageName: string, config?: IDictionary<string | boolean>, path?: string): Promise<string>;
6+
public abstract view(packageName: string, config: Object): Promise<any>;
7+
public abstract search(filter: string[], config: IDictionary<string | boolean>): Promise<string>;
8+
public abstract searchNpms(keyword: string): Promise<INpmsResult>;
9+
public abstract getRegistryPackageData(packageName: string): Promise<any>;
10+
public abstract getCachePath(): Promise<string>;
11+
412
constructor(
513
protected $childProcess: IChildProcess,
14+
protected $fs: IFileSystem,
615
private $hostInfo: IHostInfo,
716
private $pacoteService: IPacoteService,
817
private packageManager: string
918
) { }
1019

20+
public async isRegistered(packageName: string): Promise<boolean> {
21+
if (this.isURL(packageName) || this.$fs.exists(packageName) || this.isTgz(packageName)) {
22+
return false;
23+
}
24+
25+
try {
26+
const viewResult = await this.view(packageName, { name: true });
27+
28+
// `npm view nonExistingPackageName` will return `nativescript`
29+
// if executed in the root dir of the CLI (npm 6.4.1)
30+
const packageNameRegex = new RegExp(packageName, "i");
31+
const isProperResult = packageNameRegex.test(viewResult);
32+
33+
return isProperResult;
34+
} catch (e) {
35+
return false;
36+
}
37+
}
38+
39+
public async getPackageNameParts(fullPackageName: string): Promise<INpmPackageNameParts> {
40+
// support <reserved_name>@<version> syntax, for example [email protected]
41+
// support <scoped_package_name>@<version> syntax, for example @nativescript/[email protected]
42+
const lastIndexOfAtSign = fullPackageName.lastIndexOf("@");
43+
let version = "";
44+
let templateName = "";
45+
if (lastIndexOfAtSign > 0) {
46+
templateName = fullPackageName.substr(0, lastIndexOfAtSign).toLowerCase();
47+
version = fullPackageName.substr(lastIndexOfAtSign + 1);
48+
}
49+
50+
return {
51+
name: templateName || fullPackageName,
52+
version: version
53+
};
54+
}
55+
56+
public async getPackageFullName(packageNameParts: INpmPackageNameParts): Promise<string> {
57+
return packageNameParts.version ? `${packageNameParts.name}@${packageNameParts.version}` : packageNameParts.name;
58+
}
59+
1160
protected getPackageManagerExecutableName(): string {
1261
let npmExecutableName = this.packageManager;
1362

@@ -44,7 +93,7 @@ export class BasePackageManager {
4493
array.push(`--${flag}`);
4594
array.push(`${config[flag]}`);
4695
} else if (config[flag]) {
47-
if (flag === "dist-tags" || flag === "versions") {
96+
if (flag === "dist-tags" || flag === "versions" || flag === "name") {
4897
array.push(` ${flag}`);
4998
continue;
5099
}
@@ -57,4 +106,14 @@ export class BasePackageManager {
57106

58107
return array.join(" ");
59108
}
109+
110+
private isTgz(packageName: string): boolean {
111+
return packageName.indexOf(".tgz") >= 0;
112+
}
113+
114+
private isURL(str: string): boolean {
115+
const urlRegex = '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
116+
const url = new RegExp(urlRegex, 'i');
117+
return str.length < 2083 && url.test(str);
118+
}
60119
}

lib/bootstrap.ts

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ $injector.require("androidLiveSyncService", "./services/livesync/android-livesyn
137137
$injector.require("iOSLiveSyncService", "./services/livesync/ios-livesync-service");
138138
$injector.require("usbLiveSyncService", "./services/livesync/livesync-service"); // The name is used in https://github.com/NativeScript/nativescript-dev-typescript
139139
$injector.require("previewAppLiveSyncService", "./services/livesync/playground/preview-app-livesync-service");
140+
$injector.require("previewAppLogProvider", "./services/livesync/playground/preview-app-log-provider");
140141
$injector.require("previewAppPluginsService", "./services/livesync/playground/preview-app-plugins-service");
141142
$injector.require("previewSdkService", "./services/livesync/playground/preview-sdk-service");
142143
$injector.requirePublicClass("previewDevicesService", "./services/livesync/playground/devices/preview-devices-service");

lib/commands/preview.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1+
import { DEVICE_LOG_EVENT_NAME } from "../common/constants";
2+
13
export class PreviewCommand implements ICommand {
24
public allowedParameters: ICommandParameter[] = [];
35
private static MIN_SUPPORTED_WEBPACK_VERSION = "0.17.0";
46

57
constructor(private $bundleValidatorHelper: IBundleValidatorHelper,
68
private $errors: IErrors,
79
private $liveSyncService: ILiveSyncService,
10+
private $logger: ILogger,
811
private $networkConnectivityValidator: INetworkConnectivityValidator,
912
private $projectData: IProjectData,
1013
private $options: IOptions,
14+
private $previewAppLogProvider: IPreviewAppLogProvider,
1115
private $previewQrCodeService: IPreviewQrCodeService) { }
1216

1317
public async execute(): Promise<void> {
18+
this.$previewAppLogProvider.on(DEVICE_LOG_EVENT_NAME, (deviceId: string, message: string) => {
19+
this.$logger.info(message);
20+
});
21+
1422
await this.$liveSyncService.liveSync([], {
1523
syncToPreviewApp: true,
1624
projectDir: this.$projectData.projectDir,

lib/declarations.d.ts

+29-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,27 @@ interface INodePackageManager {
2525
*/
2626
view(packageName: string, config: Object): Promise<any>;
2727

28+
/**
29+
* Checks if the specified string is name of a packaged published in the NPM registry.
30+
* @param {string} packageName The string to be checked.
31+
* @return {Promise<boolean>} True if the specified string is a registered package name, false otherwise.
32+
*/
33+
isRegistered(packageName: string): Promise<boolean>;
34+
35+
/**
36+
* Separates the package name and version from a specified fullPackageName.
37+
* @param {string} fullPackageName The full name of the package like [email protected].
38+
* @return {INpmPackageNameParts} An object containing the separated package name and version.
39+
*/
40+
getPackageNameParts(fullPackageName: string): Promise<INpmPackageNameParts>
41+
42+
/**
43+
* Returns the full name of an npm package based on the provided name and version.
44+
* @param {INpmPackageNameParts} packageNameParts An object containing the package name and version.
45+
* @return {string} The full name of the package like [email protected].
46+
*/
47+
getPackageFullName(packageNameParts: INpmPackageNameParts): Promise<string>
48+
2849
/**
2950
* Searches for a package.
3051
* @param {string[]} filter Keywords with which to perform the search.
@@ -59,6 +80,7 @@ interface IPackageInstallationManager {
5980
getLatestVersion(packageName: string): Promise<string>;
6081
getNextVersion(packageName: string): Promise<string>;
6182
getLatestCompatibleVersion(packageName: string, referenceVersion?: string): Promise<string>;
83+
getLatestCompatibleVersionSafe(packageName: string, referenceVersion?: string): Promise<string>;
6284
getInspectorFromCache(inspectorNpmPackageName: string, projectDir: string): Promise<string>;
6385
}
6486

@@ -353,6 +375,11 @@ interface INpmsPackageData {
353375
maintainers: INpmsUser[];
354376
}
355377

378+
interface INpmPackageNameParts {
379+
name: string;
380+
version: string;
381+
}
382+
356383
interface IUsername {
357384
username: string;
358385
}
@@ -537,9 +564,9 @@ interface IEnvOptions {
537564

538565
interface IAndroidBuildOptionsSettings extends IAndroidReleaseOptions, IRelease, IHasAndroidBundle { }
539566

540-
interface IHasAndroidBundle {
567+
interface IHasAndroidBundle {
541568
androidBundle?: boolean;
542-
}
569+
}
543570

544571
interface IAppFilesUpdaterOptions extends IBundle, IRelease, IOptionalWatchAllFiles, IHasUseHotModuleReloadOption { }
545572

lib/definitions/preview-app-livesync.d.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ declare global {
88
stopLiveSync(): Promise<void>;
99
}
1010

11-
interface IPreviewAppLiveSyncData extends IProjectDir, IAppFilesUpdaterOptionsComposition, IEnvOptions { }
11+
interface IPreviewAppLiveSyncData extends IProjectDir, IHasUseHotModuleReloadOption, IBundle, IEnvOptions { }
1212

1313
interface IPreviewSdkService extends EventEmitter {
1414
getQrCodeUrl(options: IHasUseHotModuleReloadOption): string;
@@ -18,10 +18,15 @@ declare global {
1818
}
1919

2020
interface IPreviewAppPluginsService {
21+
getPluginsUsageWarnings(data: IPreviewAppLiveSyncData, device: Device): string[];
2122
comparePluginsOnDevice(data: IPreviewAppLiveSyncData, device: Device): Promise<void>;
2223
getExternalPlugins(device: Device): string[];
2324
}
2425

26+
interface IPreviewAppLogProvider extends EventEmitter {
27+
logData(log: string, deviceName: string, deviceId: string): void;
28+
}
29+
2530
interface IPreviewQrCodeService {
2631
getPlaygroundAppQrCode(options?: IPlaygroundAppQrCodeOptions): Promise<IDictionary<IQrCodeImageData>>;
2732
getLiveSyncQrCode(url: string): Promise<IQrCodeImageData>;
@@ -45,5 +50,6 @@ declare global {
4550
updateConnectedDevices(devices: Device[]): void;
4651
getDeviceById(id: string): Device;
4752
getDevicesForPlatform(platform: string): Device[];
53+
getPluginsUsageWarnings(data: IPreviewAppLiveSyncData, device: Device): string[];
4854
}
4955
}

lib/definitions/project-changes.d.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
interface IAppFilesHashes {
2-
appFilesHashes: IStringDictionary;
2+
appFilesHashes?: IStringDictionary;
33
}
44

55
interface IPrepareInfo extends IAddedNativePlatform, IAppFilesHashes {
6-
time: string;
7-
bundle: boolean;
8-
release: boolean;
9-
projectFileHash: string;
10-
changesRequireBuild: boolean;
11-
changesRequireBuildTime: string;
6+
time?: string;
7+
bundle?: boolean;
8+
release?: boolean;
9+
projectFileHash?: string;
10+
changesRequireBuild?: boolean;
11+
changesRequireBuildTime?: string;
1212
iOSProvisioningProfileUUID?: string;
1313
}
1414

lib/node-package-manager.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ import { BasePackageManager } from "./base-package-manager";
33
import { exported, cache } from "./common/decorators";
44
import { CACACHE_DIRECTORY_NAME } from "./constants";
55

6-
export class NodePackageManager extends BasePackageManager implements INodePackageManager {
6+
export class NodePackageManager extends BasePackageManager {
77
constructor(
88
$childProcess: IChildProcess,
99
private $errors: IErrors,
10-
private $fs: IFileSystem,
10+
$fs: IFileSystem,
1111
$hostInfo: IHostInfo,
1212
private $logger: ILogger,
1313
private $httpClient: Server.IHttpClient,
1414
$pacoteService: IPacoteService) {
15-
super($childProcess, $hostInfo, $pacoteService, 'npm');
15+
super($childProcess, $fs, $hostInfo, $pacoteService, 'npm');
1616
}
1717

1818
@exported("npm")

lib/package-installation-manager.ts

+13-17
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ export class PackageInstallationManager implements IPackageInstallationManager {
3939
return maxSatisfying || latestVersion;
4040
}
4141

42+
public async getLatestCompatibleVersionSafe(packageName: string, referenceVersion?: string): Promise<string> {
43+
let version = "";
44+
const canGetVersionFromNpm = await this.$packageManager.isRegistered(packageName);
45+
if (canGetVersionFromNpm) {
46+
version = await this.getLatestCompatibleVersion(packageName, referenceVersion);
47+
}
48+
49+
return version;
50+
}
51+
4252
public async install(packageToInstall: string, projectDir: string, opts?: INpmInstallOptions): Promise<any> {
4353
try {
4454
const pathToSave = projectDir;
@@ -101,6 +111,7 @@ export class PackageInstallationManager implements IPackageInstallationManager {
101111
if (this.$fs.exists(pathToInspector)) {
102112
return true;
103113
}
114+
104115
return false;
105116
}
106117

@@ -110,28 +121,13 @@ export class PackageInstallationManager implements IPackageInstallationManager {
110121
packageName = possiblePackageName;
111122
}
112123

113-
// check if the packageName is url or local file and if it is, let npm install deal with the version
114-
if (this.isURL(packageName) || this.$fs.exists(packageName) || this.isTgz(packageName)) {
115-
version = null;
116-
} else {
117-
version = version || await this.getLatestCompatibleVersion(packageName);
118-
}
119-
124+
version = version || await this.getLatestCompatibleVersionSafe(packageName);
120125
const installResultInfo = await this.npmInstall(packageName, pathToSave, version, dependencyType);
121126
const installedPackageName = installResultInfo.name;
122127

123128
const pathToInstalledPackage = path.join(pathToSave, "node_modules", installedPackageName);
124-
return pathToInstalledPackage;
125-
}
126129

127-
private isTgz(packageName: string): boolean {
128-
return packageName.indexOf(".tgz") >= 0;
129-
}
130-
131-
private isURL(str: string): boolean {
132-
const urlRegex = '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
133-
const url = new RegExp(urlRegex, 'i');
134-
return str.length < 2083 && url.test(str);
130+
return pathToInstalledPackage;
135131
}
136132

137133
private async npmInstall(packageName: string, pathToSave: string, version: string, dependencyType: string): Promise<INpmInstallResultInfo> {

lib/package-manager.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export class PackageManager implements INodePackageManager {
99
private $options: IOptions,
1010
private $yarn: INodePackageManager,
1111
private $userSettingsService: IUserSettingsService
12-
) {}
12+
) { }
1313

1414
@cache()
1515
protected async init(): Promise<void> {
@@ -42,6 +42,21 @@ export class PackageManager implements INodePackageManager {
4242
return this.packageManager.searchNpms(keyword);
4343
}
4444

45+
@invokeInit()
46+
public async isRegistered(packageName: string): Promise<boolean> {
47+
return this.packageManager.isRegistered(packageName);
48+
}
49+
50+
@invokeInit()
51+
public async getPackageFullName(packageNameParts: INpmPackageNameParts): Promise<string> {
52+
return this.packageManager.getPackageFullName(packageNameParts);
53+
}
54+
55+
@invokeInit()
56+
public async getPackageNameParts(fullPackageName: string): Promise<INpmPackageNameParts> {
57+
return this.packageManager.getPackageNameParts(fullPackageName);
58+
}
59+
4560
@invokeInit()
4661
public getRegistryPackageData(packageName: string): Promise<any> {
4762
return this.packageManager.getRegistryPackageData(packageName);

0 commit comments

Comments
 (0)