diff --git a/lib/android-tools-info.ts b/lib/android-tools-info.ts index 6e9ba1d6ff..17119dfb16 100644 --- a/lib/android-tools-info.ts +++ b/lib/android-tools-info.ts @@ -92,7 +92,7 @@ export class AndroidToolsInfo implements IAndroidToolsInfo { */ private printMessage(msg: string, showWarningsAsErrors: boolean): void { if (showWarningsAsErrors) { - this.$errors.failWithoutHelp(msg); + this.$errors.fail(msg); } else { this.$logger.warn(msg); } @@ -104,7 +104,7 @@ export class AndroidToolsInfo implements IAndroidToolsInfo { if (userSpecifiedCompileSdk) { const androidCompileSdk = `${androidToolsInfo.ANDROID_TARGET_PREFIX}-${userSpecifiedCompileSdk}`; if (!_.includes(installedTargets, androidCompileSdk)) { - this.$errors.failWithoutHelp(`You have specified '${userSpecifiedCompileSdk}' for compile sdk, but it is not installed on your system.`); + this.$errors.fail(`You have specified '${userSpecifiedCompileSdk}' for compile sdk, but it is not installed on your system.`); } return userSpecifiedCompileSdk; diff --git a/lib/commands/add-platform.ts b/lib/commands/add-platform.ts index b21878006d..5782e8c334 100644 --- a/lib/commands/add-platform.ts +++ b/lib/commands/add-platform.ts @@ -9,17 +9,17 @@ export class AddPlatformCommand extends ValidatePlatformCommandBase implements I $projectData: IProjectData, $platformsDataService: IPlatformsDataService, private $errors: IErrors) { - super($options, $platformsDataService, $platformValidationService, $projectData); - this.$projectData.initializeProjectData(); + super($options, $platformsDataService, $platformValidationService, $projectData); + this.$projectData.initializeProjectData(); } public async execute(args: string[]): Promise { await this.$platformCommandHelper.addPlatforms(args, this.$projectData, this.$options.frameworkPath); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { if (!args || args.length === 0) { - this.$errors.fail("No platform specified. Please specify a platform to add"); + this.$errors.failWithHelp("No platform specified. Please specify a platform to add."); } let canExecute = true; @@ -27,17 +27,13 @@ export class AddPlatformCommand extends ValidatePlatformCommandBase implements I this.$platformValidationService.validatePlatform(arg, this.$projectData); if (!this.$platformValidationService.isPlatformSupportedForOS(arg, this.$projectData)) { - this.$errors.fail(`Applications for platform ${arg} can not be built on this OS`); + this.$errors.fail(`Applications for platform ${arg} cannot be built on this OS`); } - const output = await super.canExecuteCommandBase(arg); - canExecute = canExecute && output.canExecute; + canExecute = await super.canExecuteCommandBase(arg); } - return { - canExecute, - suppressCommandHelp: !canExecute - }; + return canExecute; } } diff --git a/lib/commands/appstore-list.ts b/lib/commands/appstore-list.ts index 94acbabec3..6ed4569530 100644 --- a/lib/commands/appstore-list.ts +++ b/lib/commands/appstore-list.ts @@ -37,7 +37,7 @@ export class ListiOSApps implements ICommand { this.$logger.info("Seems you don't have any applications yet."); } else { const table: any = createTable(["Application Name", "Bundle Identifier", "In Flight Version"], applications.map(application => { - const version = (application && application.versionSets && application.versionSets.length && application.versionSets[0].inFlightVersion && application.versionSets[0].inFlightVersion.version) || ""; + const version = (application && application.versionSets && application.versionSets.length && application.versionSets[0].inFlightVersion && application.versionSets[0].inFlightVersion.version) || ""; return [application.name, application.bundleId, version]; })); diff --git a/lib/commands/appstore-upload.ts b/lib/commands/appstore-upload.ts index e8dfc56508..0dab27877e 100644 --- a/lib/commands/appstore-upload.ts +++ b/lib/commands/appstore-upload.ts @@ -79,7 +79,7 @@ export class PublishIOS implements ICommand { public async canExecute(args: string[]): Promise { if (!this.$hostInfo.isDarwin) { - this.$errors.failWithoutHelp("iOS publishing is only available on Mac OS X."); + this.$errors.fail("iOS publishing is only available on macOS."); } if (!this.$platformValidationService.isPlatformSupportedForOS(this.$devicePlatformsConstants.iOS, this.$projectData)) { diff --git a/lib/commands/build.ts b/lib/commands/build.ts index 86686e4688..fd66257f21 100644 --- a/lib/commands/build.ts +++ b/lib/commands/build.ts @@ -34,20 +34,13 @@ export abstract class BuildCommandBase extends ValidatePlatformCommandBase { } } - protected async validateArgs(args: string[], platform: string): Promise { - const canExecute = await this.validateArgsCore(args, platform); - return { - canExecute, - suppressCommandHelp: false - }; - } - - private async validateArgsCore(args: string[], platform: string): Promise { + protected async validateArgs(args: string[], platform: string): Promise { if (args.length !== 0) { - return false; + this.$errors.failWithHelp(`The arguments '${args.join(" ")}' are not valid for the current command.`); } const result = await this.$platformValidationService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, platform); + return result; } } @@ -72,7 +65,7 @@ export class BuildIosCommand extends BuildCommandBase implements ICommand { await this.executeCore([this.$devicePlatformsConstants.iOS.toLowerCase()]); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { const platform = this.$devicePlatformsConstants.iOS; if (!this.$options.force) { await this.$migrateController.validate({ projectDir: this.$projectData.projectDir, platforms: [platform] }); @@ -80,12 +73,12 @@ export class BuildIosCommand extends BuildCommandBase implements ICommand { super.validatePlatform(platform); - let result = await super.canExecuteCommandBase(platform, { notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true } }); - if (result.canExecute) { - result = await super.validateArgs(args, platform); + let canExecute = await super.canExecuteCommandBase(platform, { notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true } }); + if (canExecute) { + canExecute = await super.validateArgs(args, platform); } - return result; + return canExecute; } } @@ -120,22 +113,22 @@ export class BuildAndroidCommand extends BuildCommandBase implements ICommand { } } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { const platform = this.$devicePlatformsConstants.Android; if (!this.$options.force) { await this.$migrateController.validate({ projectDir: this.$projectData.projectDir, platforms: [platform] }); } this.$androidBundleValidatorHelper.validateRuntimeVersion(this.$projectData); - let result = await super.canExecuteCommandBase(platform, { notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true } }); - if (result.canExecute) { + let canExecute = await super.canExecuteCommandBase(platform, { notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true } }); + if (canExecute) { if (this.$options.release && (!this.$options.keyStorePath || !this.$options.keyStorePassword || !this.$options.keyStoreAlias || !this.$options.keyStoreAliasPassword)) { - this.$errors.fail(ANDROID_RELEASE_BUILD_ERROR_MESSAGE); + this.$errors.failWithHelp(ANDROID_RELEASE_BUILD_ERROR_MESSAGE); } - result = await super.validateArgs(args, platform); + canExecute = await super.validateArgs(args, platform); } - return result; + return canExecute; } } diff --git a/lib/commands/command-base.ts b/lib/commands/command-base.ts index 7621f92a69..af2b6af166 100644 --- a/lib/commands/command-base.ts +++ b/lib/commands/command-base.ts @@ -7,15 +7,14 @@ export abstract class ValidatePlatformCommandBase { abstract allowedParameters: ICommandParameter[]; abstract execute(args: string[]): Promise; - public async canExecuteCommandBase(platform: string, options?: ICanExecuteCommandOptions): Promise { + public async canExecuteCommandBase(platform: string, options?: ICanExecuteCommandOptions): Promise { options = options || {}; const validatePlatformOutput = await this.validatePlatformBase(platform, options.notConfiguredEnvOptions); const canExecute = this.canExecuteCommand(validatePlatformOutput); - let result = { canExecute, suppressCommandHelp: !canExecute }; + let result = canExecute; if (canExecute && options.validateOptions) { - const validateOptionsOutput = await this.$platformValidationService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, platform); - result = { canExecute: validateOptionsOutput, suppressCommandHelp: false }; + result = await this.$platformValidationService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, platform); } return result; diff --git a/lib/commands/create-project.ts b/lib/commands/create-project.ts index e19d0f4658..9c253c733a 100644 --- a/lib/commands/create-project.ts +++ b/lib/commands/create-project.ts @@ -31,7 +31,7 @@ export class CreateProjectCommand implements ICommand { }; if ((this.$options.tsc || this.$options.ng || this.$options.vue || this.$options.js) && this.$options.template) { - this.$errors.fail("You cannot use a flavor option like --ng, --vue, --tsc and --js together with --template."); + this.$errors.failWithHelp("You cannot use a flavor option like --ng, --vue, --tsc and --js together with --template."); } let projectName = args[0]; diff --git a/lib/commands/debug.ts b/lib/commands/debug.ts index 1bdc9c50b3..e23d2aa9aa 100644 --- a/lib/commands/debug.ts +++ b/lib/commands/debug.ts @@ -52,7 +52,7 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements }); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { if (!this.$options.force) { await this.$migrateController.validate({ projectDir: this.$projectData.projectDir, platforms: [this.platform] }); } @@ -64,7 +64,7 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements } if (this.$options.release) { - this.$errors.fail("--release flag is not applicable to this command"); + this.$errors.failWithHelp("--release flag is not applicable to this command."); } const result = await super.canExecuteCommandBase(this.platform, { validateOptions: true, notConfiguredEnvOptions: { hideCloudBuildOption: true, hideSyncToPreviewAppOption: true } }); @@ -103,7 +103,7 @@ export class DebugIOSCommand implements ICommand { return this.debugPlatformCommand.execute(args); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { if (!this.$platformValidationService.isPlatformSupportedForOS(this.$devicePlatformsConstants.iOS, this.$projectData)) { this.$errors.fail(`Applications for platform ${this.$devicePlatformsConstants.iOS} can not be built on this OS`); } @@ -164,7 +164,7 @@ export class DebugAndroidCommand implements ICommand { public execute(args: string[]): Promise { return this.debugPlatformCommand.execute(args); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { const result = await this.debugPlatformCommand.canExecute(args); return result; } diff --git a/lib/commands/deploy.ts b/lib/commands/deploy.ts index ae414976c6..05e85066ca 100644 --- a/lib/commands/deploy.ts +++ b/lib/commands/deploy.ts @@ -19,8 +19,8 @@ export class DeployOnDeviceCommand extends ValidatePlatformCommandBase implement $platformsDataService: IPlatformsDataService, private $deployCommandHelper: DeployCommandHelper, private $androidBundleValidatorHelper: IAndroidBundleValidatorHelper) { - super($options, $platformsDataService, $platformValidationService, $projectData); - this.$projectData.initializeProjectData(); + super($options, $platformsDataService, $platformValidationService, $projectData); + this.$projectData.initializeProjectData(); } public async execute(args: string[]): Promise { @@ -28,7 +28,7 @@ export class DeployOnDeviceCommand extends ValidatePlatformCommandBase implement await this.$deployCommandHelper.deploy(platform); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { this.$androidBundleValidatorHelper.validateNoAab(); if (!args || !args.length || args.length > 1) { return false; @@ -39,7 +39,7 @@ export class DeployOnDeviceCommand extends ValidatePlatformCommandBase implement } if (this.$mobileHelper.isAndroidPlatform(args[0]) && this.$options.release && (!this.$options.keyStorePath || !this.$options.keyStorePassword || !this.$options.keyStoreAlias || !this.$options.keyStoreAliasPassword)) { - this.$errors.fail(ANDROID_RELEASE_BUILD_ERROR_MESSAGE); + this.$errors.failWithHelp(ANDROID_RELEASE_BUILD_ERROR_MESSAGE); } const result = await super.canExecuteCommandBase(args[0], { validateOptions: true }); diff --git a/lib/commands/generate.ts b/lib/commands/generate.ts index 4170f0d54c..a342b49aa2 100644 --- a/lib/commands/generate.ts +++ b/lib/commands/generate.ts @@ -12,7 +12,7 @@ export class GenerateCommand implements ICommand { try { await run(this.executionOptions); } catch (error) { - this.$errors.failWithoutHelp(error.message); + this.$errors.fail(error.message); } } @@ -25,7 +25,7 @@ export class GenerateCommand implements ICommand { private validateExecutionOptions() { if (!this.executionOptions.schematic) { - this.$errors.fail(`The generate command requires a schematic name to be specified.`); + this.$errors.failWithHelp(`The generate command requires a schematic name to be specified.`); } } diff --git a/lib/commands/platform-clean.ts b/lib/commands/platform-clean.ts index 4d1bb7e39b..ce0c3ee4e3 100644 --- a/lib/commands/platform-clean.ts +++ b/lib/commands/platform-clean.ts @@ -18,7 +18,7 @@ export class CleanCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!args || args.length === 0) { - this.$errors.fail("No platform specified. Please specify a platform to clean"); + this.$errors.failWithHelp("No platform specified. Please specify a platform to clean."); } _.each(args, platform => { diff --git a/lib/commands/plugin/add-plugin.ts b/lib/commands/plugin/add-plugin.ts index a2830b007d..8bd9442d63 100644 --- a/lib/commands/plugin/add-plugin.ts +++ b/lib/commands/plugin/add-plugin.ts @@ -4,8 +4,8 @@ export class AddPluginCommand implements ICommand { constructor(private $pluginsService: IPluginsService, private $projectData: IProjectData, private $errors: IErrors) { - this.$projectData.initializeProjectData(); - } + this.$projectData.initializeProjectData(); + } public async execute(args: string[]): Promise { return this.$pluginsService.add(args[0], this.$projectData); @@ -13,13 +13,13 @@ export class AddPluginCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!args[0]) { - this.$errors.fail("You must specify plugin name."); + this.$errors.failWithHelp("You must specify plugin name."); } const installedPlugins = await this.$pluginsService.getAllInstalledPlugins(this.$projectData); const pluginName = args[0].toLowerCase(); if (_.some(installedPlugins, (plugin: IPluginData) => plugin.name.toLowerCase() === pluginName)) { - this.$errors.failWithoutHelp(`Plugin "${pluginName}" is already installed.`); + this.$errors.fail(`Plugin "${pluginName}" is already installed.`); } return true; diff --git a/lib/commands/plugin/build-plugin.ts b/lib/commands/plugin/build-plugin.ts index 27be1fed5f..390da7a596 100644 --- a/lib/commands/plugin/build-plugin.ts +++ b/lib/commands/plugin/build-plugin.ts @@ -54,7 +54,7 @@ export class BuildPluginCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!this.$fs.exists(path.join(this.pluginProjectPath, constants.PLATFORMS_DIR_NAME, "android"))) { - this.$errors.failWithoutHelp("No plugin found at the current directory, or the plugin does not need to have its platforms/android components built into an `.aar`."); + this.$errors.fail("No plugin found at the current directory, or the plugin does not need to have its platforms/android components built into an `.aar`."); } return true; diff --git a/lib/commands/plugin/create-plugin.ts b/lib/commands/plugin/create-plugin.ts index 30bf15538a..397e82ece9 100644 --- a/lib/commands/plugin/create-plugin.ts +++ b/lib/commands/plugin/create-plugin.ts @@ -42,7 +42,7 @@ export class CreatePluginCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!args[0]) { - this.$errors.fail("You must specify the plugin repository name."); + this.$errors.failWithHelp("You must specify the plugin repository name."); } return true; diff --git a/lib/commands/plugin/remove-plugin.ts b/lib/commands/plugin/remove-plugin.ts index 9edd83df22..ea9554e0c2 100644 --- a/lib/commands/plugin/remove-plugin.ts +++ b/lib/commands/plugin/remove-plugin.ts @@ -5,8 +5,8 @@ export class RemovePluginCommand implements ICommand { private $errors: IErrors, private $logger: ILogger, private $projectData: IProjectData) { - this.$projectData.initializeProjectData(); - } + this.$projectData.initializeProjectData(); + } public async execute(args: string[]): Promise { return this.$pluginsService.remove(args[0], this.$projectData); @@ -14,7 +14,7 @@ export class RemovePluginCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!args[0]) { - this.$errors.fail("You must specify plugin name."); + this.$errors.failWithHelp("You must specify plugin name."); } let pluginNames: string[] = []; @@ -29,7 +29,7 @@ export class RemovePluginCommand implements ICommand { const pluginName = args[0].toLowerCase(); if (!_.some(pluginNames, name => name.toLowerCase() === pluginName)) { - this.$errors.failWithoutHelp(`Plugin "${pluginName}" is not installed.`); + this.$errors.fail(`Plugin "${pluginName}" is not installed.`); } return true; diff --git a/lib/commands/plugin/update-plugin.ts b/lib/commands/plugin/update-plugin.ts index d0b9db4f83..f456c53f78 100644 --- a/lib/commands/plugin/update-plugin.ts +++ b/lib/commands/plugin/update-plugin.ts @@ -29,7 +29,7 @@ export class UpdatePluginCommand implements ICommand { const pluginName = args[0].toLowerCase(); if (!_.some(installedPluginNames, name => name.toLowerCase() === pluginName)) { - this.$errors.failWithoutHelp(`Plugin "${pluginName}" is not installed.`); + this.$errors.fail(`Plugin "${pluginName}" is not installed.`); } return true; diff --git a/lib/commands/prepare.ts b/lib/commands/prepare.ts index 0e42bdd1aa..727be490bb 100644 --- a/lib/commands/prepare.ts +++ b/lib/commands/prepare.ts @@ -29,7 +29,7 @@ export class PrepareCommand extends ValidatePlatformCommandBase implements IComm await this.$prepareController.prepare(prepareData); } - public async canExecute(args: string[]): Promise { + public async canExecute(args: string[]): Promise { const platform = args[0]; const result = await this.$platformCommandParameter.validate(platform) && await this.$platformValidationService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, platform); diff --git a/lib/commands/preview.ts b/lib/commands/preview.ts index 21249fec62..6459312f0d 100644 --- a/lib/commands/preview.ts +++ b/lib/commands/preview.ts @@ -38,7 +38,7 @@ export class PreviewCommand implements ICommand { public async canExecute(args: string[]): Promise { if (args && args.length) { - this.$errors.fail(`The arguments '${args.join(" ")}' are not valid for the preview command.`); + this.$errors.failWithHelp(`The ${args.length > 1 ? "arguments" : "argument"} '${args.join(" ")}' ${args.length > 1 ? "are" : "is"} not valid for the preview command.`); } if (!this.$options.force) { diff --git a/lib/commands/remove-platform.ts b/lib/commands/remove-platform.ts index 92fbd50f5f..18481566a6 100644 --- a/lib/commands/remove-platform.ts +++ b/lib/commands/remove-platform.ts @@ -6,7 +6,7 @@ export class RemovePlatformCommand implements ICommand { private $platformCommandHelper: IPlatformCommandHelper, private $platformValidationService: IPlatformValidationService, private $projectData: IProjectData - ) { + ) { this.$projectData.initializeProjectData(); } @@ -16,7 +16,7 @@ export class RemovePlatformCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!args || args.length === 0) { - this.$errors.fail("No platform specified. Please specify a platform to remove"); + this.$errors.failWithHelp("No platform specified. Please specify a platform to remove."); } _.each(args, platform => { diff --git a/lib/commands/resources/resources-update.ts b/lib/commands/resources/resources-update.ts index 4bc224aa8f..7fd0ecfb3a 100644 --- a/lib/commands/resources/resources-update.ts +++ b/lib/commands/resources/resources-update.ts @@ -19,11 +19,11 @@ export class ResourcesUpdateCommand implements ICommand { for (const platform of args) { if (!this.$androidResourcesMigrationService.canMigrate(platform)) { - this.$errors.failWithoutHelp(`The ${platform} does not need to have its resources updated.`); + this.$errors.fail(`The ${platform} does not need to have its resources updated.`); } if (this.$androidResourcesMigrationService.hasMigrated(this.$projectData.getAppResourcesDirectoryPath())) { - this.$errors.failWithoutHelp("The App_Resources have already been updated for the Android platform."); + this.$errors.fail("The App_Resources have already been updated for the Android platform."); } } diff --git a/lib/commands/run.ts b/lib/commands/run.ts index 7348c63c58..669ad67efc 100644 --- a/lib/commands/run.ts +++ b/lib/commands/run.ts @@ -26,7 +26,7 @@ export class RunCommandBase implements ICommand { public async canExecute(args: string[]): Promise { if (args.length) { - this.$errors.fail(ERROR_NO_VALID_SUBCOMMAND_FORMAT, "run"); + this.$errors.failWithHelp(ERROR_NO_VALID_SUBCOMMAND_FORMAT, "run"); } this.platform = args[0] || this.platform; @@ -127,7 +127,7 @@ export class RunAndroidCommand implements ICommand { } if (this.$options.release && (!this.$options.keyStorePath || !this.$options.keyStorePassword || !this.$options.keyStoreAlias || !this.$options.keyStoreAliasPassword)) { - this.$errors.fail(ANDROID_RELEASE_BUILD_ERROR_MESSAGE); + this.$errors.failWithHelp(ANDROID_RELEASE_BUILD_ERROR_MESSAGE); } return this.$platformValidationService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, this.$devicePlatformsConstants.Android.toLowerCase()); diff --git a/lib/commands/test-init.ts b/lib/commands/test-init.ts index fb0985fa65..2a6af3c250 100644 --- a/lib/commands/test-init.ts +++ b/lib/commands/test-init.ts @@ -28,7 +28,7 @@ class TestInitCommand implements ICommand { const frameworkToInstall = this.$options.framework || await this.$prompter.promptForChoice('Select testing framework:', TESTING_FRAMEWORKS); if (TESTING_FRAMEWORKS.indexOf(frameworkToInstall) === -1) { - this.$errors.fail(`Unknown or unsupported unit testing framework: ${frameworkToInstall}`); + this.$errors.failWithHelp(`Unknown or unsupported unit testing framework: ${frameworkToInstall}.`); } const projectFilesExtension = this.$projectData.projectType === ProjectTypes.TsFlavorName || this.$projectData.projectType === ProjectTypes.NgFlavorName ? ".ts" : ".js"; @@ -37,7 +37,7 @@ class TestInitCommand implements ICommand { try { modulesToInstall = this.$testInitializationService.getDependencies(frameworkToInstall); } catch (err) { - this.$errors.failWithoutHelp(`Unable to install the unit testing dependencies. Error: '${err.message}'`); + this.$errors.fail(`Unable to install the unit testing dependencies. Error: '${err.message}'`); } modulesToInstall = modulesToInstall.filter(moduleToInstall => !moduleToInstall.projectType || moduleToInstall.projectType === projectFilesExtension); diff --git a/lib/commands/test.ts b/lib/commands/test.ts index e412e72ab0..a238ee38a6 100644 --- a/lib/commands/test.ts +++ b/lib/commands/test.ts @@ -48,7 +48,7 @@ abstract class TestCommandBase { await this.$testExecutionService.startKarmaServer(this.platform, liveSyncInfo, deviceDescriptors); } - async canExecute(args: string[]): Promise { + async canExecute(args: string[]): Promise { if (!this.$options.force) { await this.$migrateController.validate({ projectDir: this.$projectData.projectDir, platforms: [this.platform] }); } @@ -71,7 +71,6 @@ abstract class TestCommandBase { if (!canStartKarmaServer) { this.$errors.fail({ formatStr: "Error: In order to run unit tests, your project must already be configured by running $ tns test init.", - suppressCommandHelp: true, errorCode: ErrorCodes.TESTS_INIT_REQUIRED }); } diff --git a/lib/commands/update-platform.ts b/lib/commands/update-platform.ts index b6a6f98f8d..6b46dfe6da 100644 --- a/lib/commands/update-platform.ts +++ b/lib/commands/update-platform.ts @@ -18,7 +18,7 @@ export class UpdatePlatformCommand implements ICommand { public async canExecute(args: string[]): Promise { if (!args || args.length === 0) { - this.$errors.fail("No platform specified. Please specify platforms to update."); + this.$errors.failWithHelp("No platform specified. Please specify platforms to update."); } _.each(args, arg => { @@ -27,7 +27,7 @@ export class UpdatePlatformCommand implements ICommand { }); for (const arg of args) { - const [ platform, versionToBeInstalled ] = arg.split("@"); + const [platform, versionToBeInstalled] = arg.split("@"); const checkEnvironmentRequirementsInput: ICheckEnvironmentRequirementsInput = { platform, options: this.$options }; // If version is not specified, we know the command will install the latest compatible Android runtime. // The latest compatible Android runtime supports Java version, so we do not need to pass it here. diff --git a/lib/commands/update.ts b/lib/commands/update.ts index 28b8ee1302..bcade39577 100644 --- a/lib/commands/update.ts +++ b/lib/commands/update.ts @@ -30,7 +30,7 @@ export class UpdateCommand implements ICommand { }); if (shouldMigrate) { - this.$errors.failWithoutHelp(UpdateCommand.SHOULD_MIGRATE_PROJECT_MESSAGE); + this.$errors.fail(UpdateCommand.SHOULD_MIGRATE_PROJECT_MESSAGE); } return args.length < 2 && this.$projectData.projectDir !== ""; diff --git a/lib/common/child-process.ts b/lib/common/child-process.ts index 125ec99592..771e44f98d 100644 --- a/lib/common/child-process.ts +++ b/lib/common/child-process.ts @@ -9,7 +9,7 @@ export class ChildProcess extends EventEmitter implements IChildProcess { public async exec(command: string, options?: any, execOptions?: IExecOptions): Promise { return new Promise((resolve, reject) => { - const callback = (error: Error, stdout: string | NodeBuffer, stderr: string | NodeBuffer) => { + const callback = (error: Error, stdout: string | Buffer, stderr: string | Buffer) => { this.$logger.trace("Exec %s \n stdout: %s \n stderr: %s", command, stdout.toString(), stderr.toString()); if (error) { @@ -33,7 +33,7 @@ export class ChildProcess extends EventEmitter implements IChildProcess { this.$logger.debug("execFile: %s %s", command, this.getArgumentsAsQuotedString(args)); return new Promise((resolve, reject) => { - child_process.execFile(command, args, (error: any, stdout: string | NodeBuffer) => { + child_process.execFile(command, args, (error: any, stdout: string | Buffer) => { if (error) { reject(error); } else { @@ -179,7 +179,7 @@ export class ChildProcess extends EventEmitter implements IChildProcess { return this.spawnFromEvent(command, args, event, undefined, { throwError: false }); } catch (e) { const message = (e.code === "ENOENT") ? errorMessage : e.message; - this.$errors.failWithoutHelp(message); + this.$errors.fail(message); } } diff --git a/lib/common/commands/analytics.ts b/lib/common/commands/analytics.ts index bc35003138..a9acd9340e 100644 --- a/lib/common/commands/analytics.ts +++ b/lib/common/commands/analytics.ts @@ -10,7 +10,7 @@ export class AnalyticsCommandParameter implements ICommandParameter { case "": return true; default: - this.$errors.fail(`The value '${validationValue}' is not valid. Valid values are 'enable', 'disable' and 'status'.`); + this.$errors.failWithHelp(`The value '${validationValue}' is not valid. Valid values are 'enable', 'disable' and 'status'.`); } } } diff --git a/lib/common/commands/device/device-log-stream.ts b/lib/common/commands/device/device-log-stream.ts index 37b4ad0e2d..d7d9053818 100644 --- a/lib/common/commands/device/device-log-stream.ts +++ b/lib/common/commands/device/device-log-stream.ts @@ -9,9 +9,9 @@ export class OpenDeviceLogStreamCommand implements ICommand { private $loggingLevels: Mobile.ILoggingLevels, $iOSSimulatorLogProvider: Mobile.IiOSSimulatorLogProvider, $cleanupService: ICleanupService) { - $iOSSimulatorLogProvider.setShouldDispose(false); - $cleanupService.setShouldDispose(false); - } + $iOSSimulatorLogProvider.setShouldDispose(false); + $cleanupService.setShouldDispose(false); + } allowedParameters: ICommandParameter[] = []; @@ -22,7 +22,7 @@ export class OpenDeviceLogStreamCommand implements ICommand { if (this.$devicesService.deviceCount > 1) { await this.$commandsService.tryExecuteCommand("device", []); - this.$errors.fail(OpenDeviceLogStreamCommand.NOT_SPECIFIED_DEVICE_ERROR_MESSAGE); + this.$errors.failWithHelp(OpenDeviceLogStreamCommand.NOT_SPECIFIED_DEVICE_ERROR_MESSAGE); } const action = (device: Mobile.IiOSDevice) => device.openDeviceLogStream(); diff --git a/lib/common/commands/device/get-file.ts b/lib/common/commands/device/get-file.ts index 1b46ae267e..3ff6cf278d 100644 --- a/lib/common/commands/device/get-file.ts +++ b/lib/common/commands/device/get-file.ts @@ -18,7 +18,7 @@ export class GetFileCommand implements ICommand { // ignore the error } if (!this.$projectData.projectIdentifiers) { - this.$errors.failWithoutHelp("Please enter application identifier or execute this command in project."); + this.$errors.fail("Please enter application identifier or execute this command in project."); } } diff --git a/lib/common/commands/device/list-devices.ts b/lib/common/commands/device/list-devices.ts index 1e49785fac..f9aa2c5dd0 100644 --- a/lib/common/commands/device/list-devices.ts +++ b/lib/common/commands/device/list-devices.ts @@ -15,7 +15,7 @@ export class ListDevicesCommand implements ICommand { if (this.$options.availableDevices) { const platform = this.$mobileHelper.normalizePlatformName(args[0]); if (!platform && args[0]) { - this.$errors.failWithoutHelp(`${args[0]} is not a valid device platform. The valid platforms are ${formatListOfNames(this.$mobileHelper.platformNames)}`); + this.$errors.fail(`${args[0]} is not a valid device platform. The valid platforms are ${formatListOfNames(this.$mobileHelper.platformNames)}`); } const availableEmulatorsOutput = await this.$devicesService.getEmulatorImages({ platform }); diff --git a/lib/common/commands/device/list-files.ts b/lib/common/commands/device/list-files.ts index 0e4ea0042a..60eb051b0d 100644 --- a/lib/common/commands/device/list-files.ts +++ b/lib/common/commands/device/list-files.ts @@ -19,7 +19,7 @@ export class ListFilesCommand implements ICommand { // ignore the error } if (!this.$projectData.projectIdentifiers) { - this.$errors.failWithoutHelp("Please enter application identifier or execute this command in project."); + this.$errors.fail("Please enter application identifier or execute this command in project."); } } diff --git a/lib/common/commands/device/put-file.ts b/lib/common/commands/device/put-file.ts index 0323c9b993..c3607e44b3 100644 --- a/lib/common/commands/device/put-file.ts +++ b/lib/common/commands/device/put-file.ts @@ -18,7 +18,7 @@ export class PutFileCommand implements ICommand { // ignore the error } if (!this.$projectData.projectIdentifiers) { - this.$errors.failWithoutHelp("Please enter application identifier or execute this command in project."); + this.$errors.fail("Please enter application identifier or execute this command in project."); } } diff --git a/lib/common/commands/device/run-application.ts b/lib/common/commands/device/run-application.ts index f749535502..3d2a33b0fd 100644 --- a/lib/common/commands/device/run-application.ts +++ b/lib/common/commands/device/run-application.ts @@ -12,7 +12,7 @@ export class RunApplicationOnDeviceCommand implements ICommand { await this.$devicesService.initialize({ deviceId: this.$options.device, skipInferPlatform: true }); if (this.$devicesService.deviceCount > 1) { - this.$errors.failWithoutHelp("More than one device found. Specify device explicitly with --device option. To discover device ID, use $%s device command.", this.$staticConfig.CLIENT_NAME.toLowerCase()); + this.$errors.failWithHelp("More than one device found. Specify device explicitly with --device option. To discover device ID, use $%s device command.", this.$staticConfig.CLIENT_NAME.toLowerCase()); } await this.$devicesService.execute(async (device: Mobile.IDevice) => await device.applicationManager.startApplication({ appId: args[0], projectName: args[1], projectDir: null })); diff --git a/lib/common/commands/package-manager-get.ts b/lib/common/commands/package-manager-get.ts index e190edc335..c6de826b6c 100644 --- a/lib/common/commands/package-manager-get.ts +++ b/lib/common/commands/package-manager-get.ts @@ -11,7 +11,7 @@ export class PackageManagerGetCommand implements ICommand { public async execute(args: string[]): Promise { if (args && args.length) { - this.$errors.fail(`The arguments '${args.join(" ")}' are not valid for the 'package-manager get' command.`); + this.$errors.failWithHelp(`The arguments '${args.join(" ")}' are not valid for the 'package-manager get' command.`); } const result = await this.$userSettingsService.getSettingValue("packageManager"); diff --git a/lib/common/commands/package-manager-set.ts b/lib/common/commands/package-manager-set.ts index 365dc8069e..1d937bba06 100644 --- a/lib/common/commands/package-manager-set.ts +++ b/lib/common/commands/package-manager-set.ts @@ -8,9 +8,9 @@ export class PackageManagerCommand implements ICommand { public allowedParameters: ICommandParameter[] = [this.$stringParameter]; public execute(args: string[]): Promise { - if (args[0] === 'yarn' ) { + if (args[0] === 'yarn') { return this.$userSettingsService.saveSetting("packageManager", "yarn"); - } else if ( args[0] === 'npm') { + } else if (args[0] === 'npm') { return this.$userSettingsService.saveSetting("packageManager", "npm"); } return this.$errors.fail(`${args[0]} is not a valid package manager. Only yarn or npm are supported.`); diff --git a/lib/common/commands/proxy/proxy-set.ts b/lib/common/commands/proxy/proxy-set.ts index 461d26c8ff..efb12d9d09 100644 --- a/lib/common/commands/proxy/proxy-set.ts +++ b/lib/common/commands/proxy/proxy-set.ts @@ -36,7 +36,7 @@ export class ProxySetCommand extends ProxyCommandBase { const noUrl = !urlString; if (noUrl) { if (!isInteractive()) { - this.$errors.fail("Console is not interactive - you need to supply all command parameters."); + this.$errors.failWithHelp("Console is not interactive - you need to supply all command parameters."); } else { urlString = await this.$prompter.getString("Url", { allowEmpty: false }); } @@ -65,9 +65,9 @@ export class ProxySetCommand extends ProxyCommandBase { if (!isInteractive()) { if (noPort) { - this.$errors.failWithoutHelp(`The port you have specified (${port || "none"}) is not valid.`); + this.$errors.fail(`The port you have specified (${port || "none"}) is not valid.`); } else if (this.isPasswordRequired(username, password)) { - this.$errors.fail("Console is not interactive - you need to supply all command parameters."); + this.$errors.failWithHelp("Console is not interactive - you need to supply all command parameters."); } } diff --git a/lib/common/constants.ts b/lib/common/constants.ts index 699647df64..74cd8be258 100644 --- a/lib/common/constants.ts +++ b/lib/common/constants.ts @@ -18,7 +18,7 @@ export const ERROR_NO_DEVICES = "Cannot find connected devices. Reconnect any co export const ERROR_CANT_USE_SIMULATOR = "You can use iOS simulator only on OS X."; export const ERROR_NO_DEVICES_CANT_USE_IOS_SIMULATOR = "Cannot find connected devices and cannot start iOS simulator on this OS."; export const ERROR_CANNOT_RESOLVE_DEVICE = "Cannot resolve the specified connected device. The provided platform does not match the provided index or identifier. To list currently connected devices and verify that the specified pair of platform and index or identifier exists, run 'device'."; -export const ERROR_NO_VALID_SUBCOMMAND_FORMAT = "The input is not valid sub-command for '%s' command"; +export const ERROR_NO_VALID_SUBCOMMAND_FORMAT = "The input is not valid sub-command for '%s' command."; export const UNREACHABLE_STATUS = "Unreachable"; export const CONNECTED_STATUS = "Connected"; diff --git a/lib/common/declarations.d.ts b/lib/common/declarations.d.ts index 815b5c1d72..3f9db042b0 100644 --- a/lib/common/declarations.d.ts +++ b/lib/common/declarations.d.ts @@ -559,13 +559,30 @@ interface IOpener { interface IErrors { fail(formatStr: string, ...args: any[]): never; - fail(opts: { formatStr?: string; errorCode?: number; suppressCommandHelp?: boolean, proxyAuthenticationRequired?: boolean, printOnStdout?: boolean }, ...args: any[]): never; + fail(opts: IFailOptions, ...args: any[]): never; + /** + * @deprecated: use `fail` instead + */ failWithoutHelp(message: string, ...args: any[]): never; + /** + * @deprecated: use `fail` instead + */ + failWithoutHelp(opts: IFailOptions, ...args: any[]): never; + failWithHelp(formatStr: string, ...args: any[]): never; + failWithHelp(opts: IFailOptions, ...args: any[]): never; beginCommand(action: () => Promise, printCommandHelp: () => Promise): Promise; verifyHeap(message: string): void; printCallStack: boolean; } +interface IFailOptions { + name?: string; + formatStr?: string; + errorCode?: number; + proxyAuthenticationRequired?: boolean; + printOnStdout?: boolean; +} + /** * Describes error raised when making http requests. */ diff --git a/lib/common/decorators.ts b/lib/common/decorators.ts index d44d174ebc..86854a5d76 100644 --- a/lib/common/decorators.ts +++ b/lib/common/decorators.ts @@ -107,14 +107,14 @@ export function performanceLog(injector?: IInjector): any { performanceService.processExecutionData(trackName, start, end, args); } else { resolvedPromise - .then(() => { - end = performanceService.now(); - performanceService.processExecutionData(trackName, start, end, args); - }) - .catch((err) => { - end = performanceService.now(); - performanceService.processExecutionData(trackName, start, end, args); - }); + .then(() => { + end = performanceService.now(); + performanceService.processExecutionData(trackName, start, end, args); + }) + .catch((err) => { + end = performanceService.now(); + performanceService.processExecutionData(trackName, start, end, args); + }); } return result; @@ -130,3 +130,53 @@ export function performanceLog(injector?: IInjector): any { return descriptor; }; } + +// inspired by https://github.com/NativeScript/NativeScript/blob/55dfe25938569edbec89255008e5ad9804901305/tns-core-modules/globals/globals.ts#L121-L137 +export function deprecated(additionalInfo?: string, injector?: IInjector): any { + const isDeprecatedMessage = " is deprecated."; + return (target: Object, key: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor => { + injector = injector || $injector; + additionalInfo = additionalInfo || ""; + const $logger = injector.resolve("logger"); + if (descriptor) { + if (descriptor.value) { + // method + const originalMethod = descriptor.value; + + descriptor.value = function (...args: any[]) { + $logger.warn(`${key.toString()}${isDeprecatedMessage} ${additionalInfo}`); + + return originalMethod.apply(this, args); + }; + + return descriptor; + } else { + // property + if (descriptor.set) { + const originalSetter = descriptor.set; + descriptor.set = function (...args: any[]) { + $logger.warn(`${key.toString()}${isDeprecatedMessage} ${additionalInfo}`); + + originalSetter.apply(this, args); + }; + } + + if (descriptor.get) { + const originalGetter = descriptor.get; + descriptor.get = function (...args: any[]) { + $logger.warn(`${key.toString()}${isDeprecatedMessage} ${additionalInfo}`); + + return originalGetter.apply(this, args); + }; + } + + return descriptor; + } + } else { + // class + $logger.warn(`${((target && ((target).name || ((target).constructor && (target).constructor.name))) || target)}${isDeprecatedMessage} ${additionalInfo}`); + + return target; + } + }; +} diff --git a/lib/common/definitions/commands.d.ts b/lib/common/definitions/commands.d.ts index 09be64927e..c8aa4176ff 100644 --- a/lib/common/definitions/commands.d.ts +++ b/lib/common/definitions/commands.d.ts @@ -10,7 +10,7 @@ interface ICommand extends ICommandOptions { // One possible case where you can use this method is when you have two commandParameters, neither of them is mandatory, // but at least one of them is required. Used in prop|add, prop|set, etc. commands as their logic is complicated and // default validation in CommandsService is not applicable. - canExecute?(args: string[]): Promise; + canExecute?(args: string[]): Promise; completionData?: string[]; dashedOptions?: IDictionary; isHierarchicalCommand?: boolean; @@ -23,15 +23,6 @@ interface ICommand extends ICommandOptions { postCommandAction?(args: string[]): Promise; } -interface ICanExecuteCommandOutput { - canExecute: boolean; - /** - * In case when canExecute method returns false, the help of the command is printed. - * In case when canExecute method returns false and suppressCommandHelp is true, the command's help will not be printed. - */ - suppressCommandHelp?: boolean; -} - interface ICanExecuteCommandOptions { validateOptions?: boolean; notConfiguredEnvOptions?: INotConfiguredEnvOptions; diff --git a/lib/common/definitions/logger.d.ts b/lib/common/definitions/logger.d.ts index 5d51828965..2f9e58422e 100644 --- a/lib/common/definitions/logger.d.ts +++ b/lib/common/definitions/logger.d.ts @@ -15,7 +15,7 @@ declare global { interface ILogger { initialize(opts?: ILoggerOptions): void; - initializeCliLogger(): void; + initializeCliLogger(opts?: ILoggerOptions): void; getLevel(): string; fatal(formatStr?: any, ...args: any[]): void; error(formatStr?: any, ...args: any[]): void; diff --git a/lib/common/dispatchers.ts b/lib/common/dispatchers.ts index db126ca6bc..89ff7aa621 100644 --- a/lib/common/dispatchers.ts +++ b/lib/common/dispatchers.ts @@ -17,7 +17,7 @@ export class CommandDispatcher implements ICommandDispatcher { if (this.$logger.getLevel() === "TRACE") { // CommandDispatcher is called from external CLI's only, so pass the path to their package.json - const sysInfo = await this.$sysInfo.getSysInfo({pathToNativeScriptCliPackageJson: path.join(__dirname, "..", "..", "package.json")}); + const sysInfo = await this.$sysInfo.getSysInfo({ pathToNativeScriptCliPackageJson: path.join(__dirname, "..", "..", "package.json") }); this.$logger.trace("System information:"); this.$logger.trace(sysInfo); } diff --git a/lib/common/errors.ts b/lib/common/errors.ts index 6d4a6353fb..c197da6d82 100644 --- a/lib/common/errors.ts +++ b/lib/common/errors.ts @@ -2,6 +2,7 @@ import * as util from "util"; import * as path from "path"; import { SourceMapConsumer } from "source-map"; import { isInteractive } from "./helpers"; +import { deprecated } from "./decorators"; // we need this to overwrite .stack property (read-only in Error) function Exception() { @@ -123,14 +124,33 @@ export class Errors implements IErrors { public printCallStack: boolean = false; - public fail(optsOrFormatStr: any, ...args: any[]): never { - const argsArray = args || []; + public fail(optsOrFormatStr: string | IFailOptions, ...args: any[]): never { + const opts = this.getFailOptions(optsOrFormatStr); + return this.failWithOptions(opts, false, ...args); + } + + @deprecated("Use `fail` instead.") + public failWithoutHelp(optsOrFormatStr: string | IFailOptions, ...args: any[]): never { + return this.fail(optsOrFormatStr, ...args); + } + public failWithHelp(optsOrFormatStr: string | IFailOptions, ...args: any[]): never { + const opts = this.getFailOptions(optsOrFormatStr); + + return this.failWithOptions(opts, true, ...args); + } + + private getFailOptions(optsOrFormatStr: string | IFailOptions): IFailOptions { let opts = optsOrFormatStr; if (_.isString(opts)) { opts = { formatStr: opts }; } + return opts; + } + + private failWithOptions(opts: IFailOptions, suggestCommandHelp: boolean, ...args: any[]): never { + const argsArray = args || []; const exception: any = new (Exception)(); exception.name = opts.name || "Exception"; exception.message = util.format.apply(null, [opts.formatStr].concat(argsArray)); @@ -140,21 +160,18 @@ export class Errors implements IErrors { } catch (err) { // Ignore } + exception.stack = (new Error(exception.message)).stack; exception.errorCode = opts.errorCode || ErrorCodes.UNKNOWN; - exception.suppressCommandHelp = opts.suppressCommandHelp; + exception.suggestCommandHelp = suggestCommandHelp; exception.proxyAuthenticationRequired = !!opts.proxyAuthenticationRequired; exception.printOnStdout = opts.printOnStdout; this.$injector.resolve("logger").trace(opts.formatStr); - throw exception; - } - public failWithoutHelp(message: string, ...args: any[]): never { - args.unshift(message); - return this.fail({ formatStr: util.format.apply(null, args), suppressCommandHelp: true }); + throw exception; } - public async beginCommand(action: () => Promise, printCommandHelp: () => Promise): Promise { + public async beginCommand(action: () => Promise, printCommandHelpSuggestion: () => Promise): Promise { try { return await action(); } catch (ex) { @@ -168,12 +185,8 @@ export class Errors implements IErrors { console.error(message); } - if (!ex.suppressCommandHelp) { - try { - await printCommandHelp(); - } catch (printHelpException) { - console.error("Failed to display command help", printHelpException); - } + if (ex.suggestCommandHelp) { + await printCommandHelpSuggestion(); } await tryTrackException(ex, this.$injector); diff --git a/lib/common/file-system.ts b/lib/common/file-system.ts index 0647d986f7..1ff4c4990f 100644 --- a/lib/common/file-system.ts +++ b/lib/common/file-system.ts @@ -177,7 +177,7 @@ export class FileSystem implements IFileSystem { return fs.readdirSync(path); } - public readFile(filename: string, options?: IReadFileOptions): string | NodeBuffer { + public readFile(filename: string, options?: IReadFileOptions): string | Buffer { return fs.readFileSync(filename, options); } @@ -203,7 +203,7 @@ export class FileSystem implements IFileSystem { return null; } - public writeFile(filename: string, data: string | NodeBuffer, encoding?: string): void { + public writeFile(filename: string, data: string | Buffer, encoding?: string): void { this.createDirectory(dirname(filename)); fs.writeFileSync(filename, data, { encoding: encoding }); } @@ -390,7 +390,7 @@ export class FileSystem implements IFileSystem { const logger: ILogger = this.$injector.resolve("$logger"); const shasumData = crypto.createHash(algorithm); const fileStream = this.createReadStream(fileName); - fileStream.on("data", (data: NodeBuffer | string) => { + fileStream.on("data", (data: Buffer | string) => { shasumData.update(data); }); diff --git a/lib/common/host-info.ts b/lib/common/host-info.ts index 4335829204..a374c4fe5e 100644 --- a/lib/common/host-info.ts +++ b/lib/common/host-info.ts @@ -108,7 +108,7 @@ export class HostInfo implements IHostInfo { await this.dotNetVersion(); return true; } catch (e) { - this.$errors.failWithoutHelp(message || "An error occurred while reading the registry."); + this.$errors.fail(message || "An error occurred while reading the registry."); } } else { return false; diff --git a/lib/common/logger/logger.ts b/lib/common/logger/logger.ts index bad1eb9442..744d338b14 100644 --- a/lib/common/logger/logger.ts +++ b/lib/common/logger/logger.ts @@ -12,9 +12,10 @@ export class Logger implements ILogger { private log4jsLogger: log4js.Logger = null; private passwordRegex = /(password=).*?(['&,]|$)|(password["']?\s*:\s*["']).*?(["'])/i; private passwordReplacement = "$1$3*******$2$4"; + private defaultLogLevel: LoggerLevel; - constructor(private $config: Config.IConfig, - private $options: IOptions) { + constructor(private $config: Config.IConfig) { + this.defaultLogLevel = this.$config.DEBUG ? LoggerLevel.TRACE : LoggerLevel.INFO; } @cache() @@ -40,7 +41,7 @@ export class Logger implements ILogger { const categories: IDictionary<{ appenders: string[]; level: string; }> = { default: { appenders: ['out'], - level: level || (this.$config.DEBUG ? "TRACE" : "INFO") + level: level || this.defaultLogLevel } }; @@ -49,12 +50,12 @@ export class Logger implements ILogger { this.log4jsLogger = log4js.getLogger(); } - public initializeCliLogger(): void { + public initializeCliLogger(opts?: ILoggerOptions): void { log4js.addLayout("cli", layout); this.initialize({ appenderOptions: { type: LoggerAppenders.cliAppender, layout: { type: "cli" } }, - level: this.$options.log + level: opts.level || this.defaultLogLevel }); } diff --git a/lib/common/mobile/android/android-application-manager.ts b/lib/common/mobile/android/android-application-manager.ts index ac116ca534..6d9158f38f 100644 --- a/lib/common/mobile/android/android-application-manager.ts +++ b/lib/common/mobile/android/android-application-manager.ts @@ -94,7 +94,7 @@ export class AndroidApplicationManager extends ApplicationManagerBase { }); } else { await this.$logcatHelper.dump(this.identifier); - this.$errors.failWithoutHelp(`Unable to find running "${appIdentifier}" application on device "${deviceIdentifier}".`); + this.$errors.fail(`Unable to find running "${appIdentifier}" application on device "${deviceIdentifier}".`); } } } diff --git a/lib/common/mobile/android/android-debug-bridge-result-handler.ts b/lib/common/mobile/android/android-debug-bridge-result-handler.ts index 27bb87ca85..7b7df5b9f0 100644 --- a/lib/common/mobile/android/android-debug-bridge-result-handler.ts +++ b/lib/common/mobile/android/android-debug-bridge-result-handler.ts @@ -267,7 +267,7 @@ export class AndroidDebugBridgeResultHandler implements Mobile.IAndroidDebugBrid if (treatErrorsAsWarnings) { this.$logger.warn(errorMessages); } else { - this.$errors.failWithoutHelp(errorMessages); + this.$errors.fail(errorMessages); } } } diff --git a/lib/common/mobile/android/android-debug-bridge.ts b/lib/common/mobile/android/android-debug-bridge.ts index 86205fa951..6aeebc3fba 100644 --- a/lib/common/mobile/android/android-debug-bridge.ts +++ b/lib/common/mobile/android/android-debug-bridge.ts @@ -66,11 +66,11 @@ export class AndroidDebugBridge implements Mobile.IAndroidDebugBridge { let errorData = ""; let isSettled = false; - result.stdout.on("data", (data: NodeBuffer) => { + result.stdout.on("data", (data: Buffer) => { adbData += data.toString(); }); - result.stderr.on("data", (data: NodeBuffer) => { + result.stderr.on("data", (data: Buffer) => { errorData += (data || "").toString(); }); diff --git a/lib/common/mobile/android/device-android-debug-bridge.ts b/lib/common/mobile/android/device-android-debug-bridge.ts index 55fdb3033d..8d9ec9727c 100644 --- a/lib/common/mobile/android/device-android-debug-bridge.ts +++ b/lib/common/mobile/android/device-android-debug-bridge.ts @@ -28,7 +28,7 @@ export class DeviceAndroidDebugBridge extends AndroidDebugBridge implements Mobi return +match[1]; } - this.$errors.failWithoutHelp("Unable to broadcast to android device:\n%s", result); + this.$errors.fail("Unable to broadcast to android device:\n%s", result); } protected async composeCommand(params: string[]): Promise { diff --git a/lib/common/mobile/android/logcat-helper.ts b/lib/common/mobile/android/logcat-helper.ts index f95117a47a..3d55cc23af 100644 --- a/lib/common/mobile/android/logcat-helper.ts +++ b/lib/common/mobile/android/logcat-helper.ts @@ -33,7 +33,7 @@ export class LogcatHelper implements Mobile.ILogcatHelper { const lineStream = byline(logcatStream.stdout); this.mapDevicesLoggingData[deviceIdentifier].loggingProcess = logcatStream; this.mapDevicesLoggingData[deviceIdentifier].lineStream = lineStream; - logcatStream.stderr.on("data", (data: NodeBuffer) => { + logcatStream.stderr.on("data", (data: Buffer) => { this.$logger.trace("ADB logcat stderr: " + data.toString()); }); @@ -49,7 +49,7 @@ export class LogcatHelper implements Mobile.ILogcatHelper { } }); - lineStream.on('data', (line: NodeBuffer) => { + lineStream.on('data', (line: Buffer) => { const lineText = line.toString(); this.$deviceLogProvider.logData(lineText, this.$devicePlatformsConstants.Android, deviceIdentifier); }); @@ -61,7 +61,7 @@ export class LogcatHelper implements Mobile.ILogcatHelper { const logcatDumpStream = await adb.executeCommand(["logcat", "-d"], { returnChildProcess: true }); const lineStream = byline(logcatDumpStream.stdout); - lineStream.on('data', (line: NodeBuffer) => { + lineStream.on('data', (line: Buffer) => { const lineText = line.toString(); this.$logger.trace(lineText); }); diff --git a/lib/common/mobile/ios/device/ios-application-manager.ts b/lib/common/mobile/ios/device/ios-application-manager.ts index 4e7d0bc44e..ceffc42591 100644 --- a/lib/common/mobile/ios/device/ios-application-manager.ts +++ b/lib/common/mobile/ios/device/ios-application-manager.ts @@ -29,7 +29,7 @@ export class IOSApplicationManager extends ApplicationManagerBase { @hook('install') public async installApplication(packageFilePath: string): Promise { await this.$iosDeviceOperations.install(packageFilePath, [this.device.deviceInfo.identifier], (err: IOSDeviceLib.IDeviceError) => { - this.$errors.failWithoutHelp(`Failed to install ${packageFilePath} on device with identifier ${err.deviceId}. Error is: ${err.message}`); + this.$errors.fail(`Failed to install ${packageFilePath} on device with identifier ${err.deviceId}. Error is: ${err.message}`); }); } @@ -58,7 +58,7 @@ export class IOSApplicationManager extends ApplicationManagerBase { public async startApplication(appData: Mobile.IStartApplicationData): Promise { if (!await this.isApplicationInstalled(appData.appId)) { - this.$errors.failWithoutHelp("Invalid application id: %s. All available application ids are: %s%s ", appData.appId, EOL, this.applicationsLiveSyncInfos.join(EOL)); + this.$errors.fail("Invalid application id: %s. All available application ids are: %s%s ", appData.appId, EOL, this.applicationsLiveSyncInfos.join(EOL)); } await this.setDeviceLogData(appData); diff --git a/lib/common/mobile/ios/ios-device-base.ts b/lib/common/mobile/ios/ios-device-base.ts index 742580689a..27645df7bc 100644 --- a/lib/common/mobile/ios/ios-device-base.ts +++ b/lib/common/mobile/ios/ios-device-base.ts @@ -55,7 +55,7 @@ export abstract class IOSDeviceBase implements Mobile.IiOSDevice { protected async getDebuggerPort(appId: string): Promise { const port = await this.$iOSDebuggerPortService.getPort({ deviceId: this.deviceInfo.identifier, appId }); if (!port) { - this.$errors.failWithoutHelp("Device socket port cannot be found."); + this.$errors.fail("Device socket port cannot be found."); } return port; diff --git a/lib/common/mobile/ios/simulator/ios-simulator-log-provider.ts b/lib/common/mobile/ios/simulator/ios-simulator-log-provider.ts index a01fcee0ed..018470a07f 100644 --- a/lib/common/mobile/ios/simulator/ios-simulator-log-provider.ts +++ b/lib/common/mobile/ios/simulator/ios-simulator-log-provider.ts @@ -10,9 +10,9 @@ export class IOSSimulatorLogProvider extends EventEmitter implements Mobile.IiOS private $logger: ILogger, private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, private $deviceLogProvider: Mobile.IDeviceLogProvider) { - super(); - this.shouldDispose = true; - } + super(); + this.shouldDispose = true; + } public setShouldDispose(shouldDispose: boolean) { this.shouldDispose = shouldDispose; @@ -22,7 +22,7 @@ export class IOSSimulatorLogProvider extends EventEmitter implements Mobile.IiOS if (!this.simulatorsLoggingEnabled[deviceId]) { const deviceLogChildProcess: ChildProcess = await this.$iOSSimResolver.iOSSim.getDeviceLogProcess(deviceId, options ? options.predicate : null); - const action = (data: NodeBuffer | string) => { + const action = (data: Buffer | string) => { const message = data.toString(); this.$deviceLogProvider.logData(message, this.$devicePlatformsConstants.iOS, deviceId); }; diff --git a/lib/common/mobile/mobile-core/android-process-service.ts b/lib/common/mobile/mobile-core/android-process-service.ts index f8a8f3397e..bd9d81d5c4 100644 --- a/lib/common/mobile/mobile-core/android-process-service.ts +++ b/lib/common/mobile/mobile-core/android-process-service.ts @@ -28,14 +28,14 @@ export class AndroidProcessService implements Mobile.IAndroidProcessService { const applicationNotStartedErrorMessage = `The application is not started on the device with identifier ${deviceIdentifier}.`; if (!processId) { - this.$errors.failWithoutHelp(applicationNotStartedErrorMessage); + this.$errors.fail(applicationNotStartedErrorMessage); } const abstractPortsInformation = await this.getAbstractPortsInformation(adb); const abstractPort = await this.getAbstractPortForApplication(adb, processId, appIdentifier, abstractPortsInformation, framework); if (!abstractPort) { - this.$errors.failWithoutHelp(applicationNotStartedErrorMessage); + this.$errors.fail(applicationNotStartedErrorMessage); } const forwardedTcpPort = await this.forwardPort({ deviceIdentifier, appIdentifier, abstractPort: `localabstract:${abstractPort}` }, adb); diff --git a/lib/common/mobile/mobile-core/devices-service.ts b/lib/common/mobile/mobile-core/devices-service.ts index ea8a843657..54a4015074 100644 --- a/lib/common/mobile/mobile-core/devices-service.ts +++ b/lib/common/mobile/mobile-core/devices-service.ts @@ -101,7 +101,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi return _.head(selectedDevices); } - this.$errors.failWithoutHelp(DebugCommandErrors.NO_DEVICES_EMULATORS_FOUND_FOR_OPTIONS); + this.$errors.fail(DebugCommandErrors.NO_DEVICES_EMULATORS_FOUND_FOR_OPTIONS); } @exported("devicesService") @@ -456,8 +456,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi } const errorMessage = `${preErrorMsg}${errors.map(e => e.message || e).join(EOL)}`; - const suppressCommandHelp = _.some(errors, (e: any) => e.suppressCommandHelp); - this.$errors.fail({ formatStr: errorMessage, suppressCommandHelp }); + this.$errors.fail(errorMessage); } return result; @@ -476,7 +475,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi identifier = appId[device.deviceInfo.platform.toLowerCase()]; } - return this.deployOnDevice(device, { packagePath, appId: identifier, projectName, projectDir}); + return this.deployOnDevice(device, { packagePath, appId: identifier, projectName, projectDir }); }); } @@ -505,7 +504,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi this.$logger.info(message); } else { if (!this.$hostInfo.isDarwin && this._platform && this.$mobileHelper.isiOSPlatform(this._platform)) { - this.$errors.failWithoutHelp(message); + this.$errors.fail(message); } else { return this.executeCore(action, canExecute); } @@ -520,7 +519,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi */ protected async startEmulatorIfNecessary(deviceInitOpts?: Mobile.IDevicesServicesInitializationOptions): Promise { if (deviceInitOpts && deviceInitOpts.deviceId && deviceInitOpts.emulator) { - this.$errors.failWithoutHelp(`--device and --emulator are incompatible options. + this.$errors.fail(`--device and --emulator are incompatible options. If you are trying to run on specific emulator, use "${this.$staticConfig.CLIENT_NAME} run --device `); } @@ -536,7 +535,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi if (!deviceInitOpts.deviceId && _.isEmpty(deviceInstances)) { if (!this.$hostInfo.isDarwin && this.$mobileHelper.isiOSPlatform(deviceInitOpts.platform)) { - this.$errors.failWithoutHelp(constants.ERROR_NO_DEVICES_CANT_USE_IOS_SIMULATOR); + this.$errors.fail(constants.ERROR_NO_DEVICES_CANT_USE_IOS_SIMULATOR); } } @@ -545,7 +544,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi } catch (err) { const errorMessage = this.getEmulatorError(err, deviceInitOpts.platform); - this.$errors.failWithoutHelp(errorMessage); + this.$errors.fail(errorMessage); } } } @@ -678,7 +677,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi if (platforms.length === 1) { this._platform = platforms[0]; } else if (platforms.length === 0) { - this.$errors.fail({ formatStr: constants.ERROR_NO_DEVICES, suppressCommandHelp: true }); + this.$errors.fail(constants.ERROR_NO_DEVICES); } else { this.$errors.fail("Multiple device platforms detected (%s). Specify platform or device on command line.", helpers.formatListOfNames(platforms, "and")); @@ -687,7 +686,7 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi } if (!this.$hostInfo.isDarwin && this._platform && this.$mobileHelper.isiOSPlatform(this._platform) && this.$options.emulator) { - this.$errors.failWithoutHelp(constants.ERROR_CANT_USE_SIMULATOR); + this.$errors.fail(constants.ERROR_CANT_USE_SIMULATOR); } this._isInitialized = true; } @@ -777,12 +776,12 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi const platform = deviceInitOpts.platform || this._platform; const emulatorServices = this.resolveEmulatorServices(platform); if (!emulatorServices) { - this.$errors.failWithoutHelp("Unable to detect platform for which to start emulator."); + this.$errors.fail("Unable to detect platform for which to start emulator."); } const result = await emulatorServices.startEmulator({ emulatorIdOrName: deviceId, imageIdentifier: deviceId, platform: platform, sdk: this._data && this._data.sdk }); if (result && result.errors && result.errors.length) { - this.$errors.failWithoutHelp(result.errors.join("\n")); + this.$errors.fail(result.errors.join("\n")); } const deviceLookingOptions = this.getDeviceLookingOptions(deviceInitOpts); diff --git a/lib/common/mobile/mobile-helper.ts b/lib/common/mobile/mobile-helper.ts index 1958451701..59746402c7 100644 --- a/lib/common/mobile/mobile-helper.ts +++ b/lib/common/mobile/mobile-helper.ts @@ -33,7 +33,7 @@ export class MobileHelper implements Mobile.IMobileHelper { public validatePlatformName(platform: string): string { if (!platform) { - this.$errors.fail("No device platform specified."); + this.$errors.failWithHelp("No device platform specified."); } const normalizedPlatform = this.normalizePlatformName(platform); @@ -41,6 +41,7 @@ export class MobileHelper implements Mobile.IMobileHelper { this.$errors.fail("'%s' is not a valid device platform. Valid platforms are %s.", platform, helpers.formatListOfNames(this.platformNames)); } + return normalizedPlatform; } diff --git a/lib/common/project-helper.ts b/lib/common/project-helper.ts index e0b34a1f7b..06bcddf07a 100644 --- a/lib/common/project-helper.ts +++ b/lib/common/project-helper.ts @@ -62,7 +62,7 @@ export class ProjectHelper implements IProjectHelper { const clientSpecificData = fileContent[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] && fileContent[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE].id; return !!clientSpecificData; } catch (err) { - this.$errors.failWithoutHelp("The project file is corrupted. Additional technical information: %s", err); + this.$errors.fail("The project file is corrupted. Additional technical information: %s", err); } } diff --git a/lib/common/services/commands-service.ts b/lib/common/services/commands-service.ts index 5b2bd90d5d..055e5819ad 100644 --- a/lib/common/services/commands-service.ts +++ b/lib/common/services/commands-service.ts @@ -25,7 +25,6 @@ export class CommandsService implements ICommandsService { private $logger: ILogger, private $options: IOptions, private $staticConfig: Config.IStaticConfig, - private $helpService: IHelpService, private $extensibilityService: IExtensibilityService, private $optionsTracker: IOptionsTracker) { } @@ -92,17 +91,20 @@ export class CommandsService implements ICommandsService { return false; } - private printHelp(commandName: string, commandArguments: string[]): Promise { - return this.$helpService.showCommandLineHelp({ commandName: this.beautifyCommandName(commandName), commandArguments }); + private printHelpSuggestion(commandName?: string): Promise { + const command = commandName ? helpers.stringReplaceAll(this.beautifyCommandName(commandName), "|", " ") + " " : ""; + const commandHelp = `tns ${command}--help`; + this.$logger.printMarkdown(`\`Run '${commandHelp}' for more information.\``); + return; } - private async executeCommandAction(commandName: string, commandArguments: string[], action: (_commandName: string, _commandArguments: string[]) => Promise): Promise { + private async executeCommandAction(commandName: string, commandArguments: string[], action: (_commandName: string, _commandArguments: string[]) => Promise): Promise { return this.$errors.beginCommand( () => action.apply(this, [commandName, commandArguments]), - () => this.printHelp(commandName, commandArguments)); + () => this.printHelpSuggestion(commandName)); } - private async tryExecuteCommandAction(commandName: string, commandArguments: string[]): Promise { + private async tryExecuteCommandAction(commandName: string, commandArguments: string[]): Promise { const command = this.$injector.resolveCommand(commandName); if (!command || !command.isHierarchicalCommand) { const dashedOptions = command ? command.dashedOptions : null; @@ -115,7 +117,6 @@ export class CommandsService implements ICommandsService { public async tryExecuteCommand(commandName: string, commandArguments: string[]): Promise { const canExecuteResult: any = await this.executeCommandAction(commandName, commandArguments, this.tryExecuteCommandAction); const canExecute = typeof canExecuteResult === "object" ? canExecuteResult.canExecute : canExecuteResult; - const suppressCommandHelp = typeof canExecuteResult === "object" ? canExecuteResult.suppressCommandHelp : false; if (canExecute) { await this.executeCommandAction(commandName, commandArguments, this.executeCommandUnchecked); @@ -123,21 +124,23 @@ export class CommandsService implements ICommandsService { // If canExecuteCommand returns false, the command cannot be executed or there's no such command at all. const command = this.$injector.resolveCommand(commandName); if (command) { - if (!suppressCommandHelp) { - // If command cannot be executed we should print its help. - await this.printHelp(commandName, commandArguments); + let commandWithArgs = commandName; + if (commandArguments && commandArguments.length) { + commandWithArgs += ` ${commandArguments.join(" ")}`; } + this.$logger.error(`Command '${commandWithArgs}' cannot be executed.`); + await this.printHelpSuggestion(commandName); } } } - private async canExecuteCommand(commandName: string, commandArguments: string[], isDynamicCommand?: boolean): Promise { + private async canExecuteCommand(commandName: string, commandArguments: string[], isDynamicCommand?: boolean): Promise { const command = this.$injector.resolveCommand(commandName); const beautifiedName = helpers.stringReplaceAll(commandName, "|", " "); if (command) { // Verify command is enabled if (command.isDisabled) { - this.$errors.failWithoutHelp("This command is not applicable to your environment."); + this.$errors.fail("This command is not applicable to your environment."); } // If command wants to handle canExecute logic on its own. @@ -154,7 +157,7 @@ export class CommandsService implements ICommandsService { return true; } - this.$errors.fail("Unable to execute command '%s'. Use '$ %s %s --help' for help.", beautifiedName, this.$staticConfig.CLIENT_NAME.toLowerCase(), beautifiedName); + this.$errors.fail(`Unable to execute command '${beautifiedName}'.`); return false; } @@ -169,7 +172,8 @@ export class CommandsService implements ICommandsService { if (extensionData) { this.$logger.warn(extensionData.installationMessage); } else { - this.$logger.fatal("Unknown command '%s'. Use '%s help' for help.", beautifiedName, this.$staticConfig.CLIENT_NAME.toLowerCase()); + this.$logger.error("Unknown command '%s'.", beautifiedName); + await this.printHelpSuggestion(); this.tryMatchCommand(commandName); } @@ -184,7 +188,7 @@ export class CommandsService implements ICommandsService { if (mandatoryParams.length > commandArguments.length) { const customErrorMessages = _.map(mandatoryParams, mp => mp.errorMessage); customErrorMessages.splice(0, 0, "You need to provide all the required parameters."); - this.$errors.fail(customErrorMessages.join(EOL)); + this.$errors.failWithHelp(customErrorMessages.join(EOL)); } // If we reach here, the commandArguments are at least as much as mandatoryParams. Now we should verify that we have each of them. @@ -202,7 +206,7 @@ export class CommandsService implements ICommandsService { if (argument) { helpers.remove(commandArgsHelper.remainingArguments, arg => arg === argument); } else { - this.$errors.fail("Missing mandatory parameter."); + this.$errors.failWithHelp("Missing mandatory parameter."); } } } @@ -220,7 +224,7 @@ export class CommandsService implements ICommandsService { // Command doesn't have any allowedParameters if (!command.allowedParameters || command.allowedParameters.length === 0) { if (commandArguments.length > 0) { - this.$errors.fail("This command doesn't accept parameters."); + this.$errors.failWithHelp("This command doesn't accept parameters."); } } else { // Exclude mandatory params, we've already checked them @@ -242,7 +246,7 @@ export class CommandsService implements ICommandsService { // Remove the matched parameter from unverifiedAllowedParams collection, so it will not be used to verify another argument. unverifiedAllowedParams.splice(index, 1); } else { - this.$errors.fail(`The parameter ${argument} is not valid for this command.`); + this.$errors.failWithHelp(`The parameter ${argument} is not valid for this command.`); } } } diff --git a/lib/common/services/help-service.ts b/lib/common/services/help-service.ts index 97b35189e0..b0f6e16b51 100644 --- a/lib/common/services/help-service.ts +++ b/lib/common/services/help-service.ts @@ -69,7 +69,7 @@ export class HelpService implements IHelpService { this.$logger.trace("Required HTML file '%s' is missing. Let's try generating HTML files and see if we'll find it.", htmlPage); await this.generateHtmlPages(); if (!this.tryOpeningSelectedPage(htmlPage)) { - this.$errors.failWithoutHelp("Unable to find help for '%s'", commandName); + this.$errors.fail("Unable to find help for '%s'", commandName); } } } @@ -208,10 +208,10 @@ export class HelpService implements IHelpService { const extensionData = await this.$extensibilityService.getExtensionNameWhereCommandIsRegistered(commandInfo); if (extensionData) { - this.$errors.failWithoutHelp(extensionData.installationMessage); + this.$errors.fail(extensionData.installationMessage); } - this.$errors.failWithoutHelp("Unknown command '%s'. Try '$ %s help' for a full list of supported commands.", commandName, this.$staticConfig.CLIENT_NAME.toLowerCase()); + this.$errors.fail("Unknown command '%s'. Try '$ %s help' for a full list of supported commands.", commandName, this.$staticConfig.CLIENT_NAME.toLowerCase()); } private static getHtmlDirFullPath(docsDir: string): string { return path.join(path.dirname(docsDir), "html"); diff --git a/lib/common/services/hooks-service.ts b/lib/common/services/hooks-service.ts index a455e1cdda..a5921228c0 100644 --- a/lib/common/services/hooks-service.ts +++ b/lib/common/services/hooks-service.ts @@ -85,7 +85,7 @@ export class HooksService implements IHooksService { } } catch (err) { this.$logger.trace(`Failed during hook execution ${hookName}.`); - this.$errors.failWithoutHelp(err.message || err); + this.$errors.fail(err.message || err); } return _.flatten(results); diff --git a/lib/common/services/net-service.ts b/lib/common/services/net-service.ts index ec377e9702..29d64788f3 100644 --- a/lib/common/services/net-service.ts +++ b/lib/common/services/net-service.ts @@ -71,7 +71,7 @@ export class Net implements INet { while (!(await this.isPortAvailable(startPort))) { startPort++; if (startPort > endPort) { - this.$errors.failWithoutHelp("Unable to find free local port."); + this.$errors.fail("Unable to find free local port."); } } @@ -80,7 +80,7 @@ export class Net implements INet { public async waitForPortToListen(waitForPortListenData: IWaitForPortListenData): Promise { if (!waitForPortListenData) { - this.$errors.failWithoutHelp("You must pass port and timeout for check."); + this.$errors.fail("You must pass port and timeout for check."); } const { timeout, port } = waitForPortListenData; @@ -105,7 +105,7 @@ export class Net implements INet { const platform = this.$osInfo.platform(); const currentPlatformData = platformData[platform]; if (!currentPlatformData) { - this.$errors.failWithoutHelp(`Unable to check for free ports on ${platform}. Supported platforms are: ${_.keys(platformData).join(", ")}`); + this.$errors.fail(`Unable to check for free ports on ${platform}. Supported platforms are: ${_.keys(platformData).join(", ")}`); } while (true) { diff --git a/lib/common/services/xcode-select-service.ts b/lib/common/services/xcode-select-service.ts index dc98cebdc7..98dd487961 100644 --- a/lib/common/services/xcode-select-service.ts +++ b/lib/common/services/xcode-select-service.ts @@ -10,14 +10,14 @@ export class XcodeSelectService implements IXcodeSelectService { public async getDeveloperDirectoryPath(): Promise { if (!this.$hostInfo.isDarwin) { - this.$errors.failWithoutHelp("xcode-select is only available on Mac OS X."); + this.$errors.fail("xcode-select is only available on Mac OS X."); } const childProcess = await this.$childProcess.spawnFromEvent("xcode-select", ["-print-path"], "close", {}, { throwError: false }), result = childProcess.stdout.trim(); if (!result) { - this.$errors.failWithoutHelp("Cannot find path to Xcode.app - make sure you've installed Xcode correctly."); + this.$errors.fail("Cannot find path to Xcode.app - make sure you've installed Xcode correctly."); } return result; @@ -32,7 +32,7 @@ export class XcodeSelectService implements IXcodeSelectService { const sysInfo = this.$injector.resolve("sysInfo"); const xcodeVer = await sysInfo.getXcodeVersion(); if (!xcodeVer) { - this.$errors.failWithoutHelp("xcodebuild execution failed. Make sure that you have latest Xcode and tools installed."); + this.$errors.fail("xcodebuild execution failed. Make sure that you have latest Xcode and tools installed."); } const xcodeVersionMatch = xcodeVer.match(/Xcode (.*)/), diff --git a/lib/common/test/unit-tests/decorators.ts b/lib/common/test/unit-tests/decorators.ts index 46e5a117a7..6cf1c81bf5 100644 --- a/lib/common/test/unit-tests/decorators.ts +++ b/lib/common/test/unit-tests/decorators.ts @@ -58,14 +58,14 @@ describe("decorators", () => { generatePublicApiFromExportedDecorator(); const actualResult: any = $injector.publicApi.__modules__[moduleName][propertyName](); assert.deepEqual(actualResult, expectedResult); - }); + }); it(`passes correct arguments to original function, when argument type is: ${_.isArray(expectedResult) ? "array" : typeof (expectedResult)}`, () => { $injector.register(moduleName, { propertyName: (arg: any) => arg }); generatePublicApiFromExportedDecorator(); const actualResult: any = $injector.publicApi.__modules__[moduleName][propertyName](expectedResult); assert.deepEqual(actualResult, expectedResult); - }); + }); }); it("returns Promise, which is resolved to correct value (function without arguments)", (done: mocha.Done) => { @@ -202,7 +202,7 @@ describe("decorators", () => { generatePublicApiFromExportedDecorator(); assert.throws(() => $injector.publicApi.__modules__[moduleName][propertyName](), errorMessage); }); - }); + }); describe("cache", () => { it("executes implementation of method only once and returns the same result each time whent it is called (number return type)", () => { @@ -433,12 +433,12 @@ describe("decorators", () => { }); _.each(expectedResults, (expectedResult: any) => { - it("returns proper result", () => { + it("returns proper result", () => { const actualResult = testInstance.testMethod(expectedResult); assert.deepEqual(actualResult, expectedResult); }); - it("returns proper result when async", () => { + it("returns proper result when async", () => { const promise = testInstance.testAsyncMehtod(expectedResult); assert.notDeepEqual(promise.then, undefined); @@ -449,20 +449,20 @@ describe("decorators", () => { }); }); - it("method has same toString", () => { + it("method has same toString", () => { assert.equal(testInstance.testMethod.toString(), undecoratedTestInstance.testMethod.toString()); }); - it("method has same name", () => { + it("method has same name", () => { assert.equal(testInstance.testMethod.name, undecoratedTestInstance.testMethod.name); }); - it("does not eat errors", () => { + it("does not eat errors", () => { assert.throws(testInstance.throwMethod, testErrorMessage); assert.isRejected(testInstance.rejectMethod(), testErrorMessage); }); - it("calls performance service on method call", async () => { + it("calls performance service on method call", async () => { const performanceService = testInjector.resolve("performanceService"); const processExecutionDataStub: sinon.SinonStub = sinon.stub(performanceService, "processExecutionData"); @@ -486,4 +486,128 @@ describe("decorators", () => { checkSubCall(processExecutionDataStub.secondCall, "TestClass__testAsyncMehtod"); }); }); + + describe("deprecated", () => { + const testDepMessage = "Just stop using this!"; + const warnings: string[] = []; + let testInjector: IInjector; + interface ITestInterface { + testField: string; + testProp: string; + depMethodWithParam(arg: any): any; + depMethodWithoutParam(): void; + depAsyncMethod(arg: any): Promise; + nonDepMethod(): any; + } + let testInstance: ITestInterface; + + function createTestInjector(): IInjector { + testInjector = new Yok(); + testInjector.register("config", {}); + testInjector.register("options", {}); + testInjector.register("logger", { + warn: (message: string) => { + warnings.push(message); + } + }); + + return testInjector; + } + + beforeEach(() => { + warnings.splice(0, warnings.length); + testInjector = createTestInjector(); + + class TestClass implements ITestInterface { + public testField: string = "test"; + + @decoratorsLib.deprecated(testDepMessage, testInjector) + public get testProp(): string { + return "hi"; + } + + public set testProp(value: string) { + return; + } + + @decoratorsLib.deprecated(testDepMessage, testInjector) + depMethodWithParam(arg: any) { + return arg; + } + + @decoratorsLib.deprecated(testDepMessage, testInjector) + depMethodWithoutParam() { + return; + } + + @decoratorsLib.deprecated(testDepMessage, testInjector) + async depAsyncMethod(arg: any) { + return Promise.resolve(arg); + } + + nonDepMethod() { + return; + } + } + + testInstance = new TestClass(); + }); + + it("method without params", () => { + testInstance.depMethodWithoutParam(); + assert.equal(warnings.length, 1); + assert.equal(warnings[0], `depMethodWithoutParam is deprecated. ${testDepMessage}`); + }); + + it("method with params", () => { + const param = 5; + const result = testInstance.depMethodWithParam(param); + assert.equal(result, param); + assert.equal(warnings.length, 1); + assert.equal(warnings[0], `depMethodWithParam is deprecated. ${testDepMessage}`); + }); + + it("async method with params", async () => { + const param = 5; + const result = await testInstance.depAsyncMethod(param); + assert.equal(result, param); + assert.equal(warnings.length, 1); + assert.equal(warnings[0], `depAsyncMethod is deprecated. ${testDepMessage}`); + }); + + it("property getter", async () => { + const result = testInstance.testProp; + assert.equal(result, "hi"); + assert.equal(warnings.length, 1); + assert.equal(warnings[0], `testProp is deprecated. ${testDepMessage}`); + }); + + it("property setter", async () => { + testInstance.testProp = "newValue"; + assert.equal(warnings.length, 1); + assert.equal(warnings[0], `testProp is deprecated. ${testDepMessage}`); + }); + + it("non deprecated field", async () => { + const result = testInstance.testField; + assert.equal(result, "test"); + assert.equal(warnings.length, 0); + }); + + it("non deprecated method", () => { + testInstance.nonDepMethod(); + assert.equal(warnings.length, 0); + }); + + it("class", async () => { + @decoratorsLib.deprecated(testDepMessage, testInjector) + class TestClassDeprecated { + } + + const depClass = new TestClassDeprecated(); + assert.isNotNull(depClass); + assert.equal(warnings.length, 1); + assert.equal(warnings[0], `TestClassDeprecated is deprecated. ${testDepMessage}`); + }); + }); }); diff --git a/lib/common/test/unit-tests/stubs.ts b/lib/common/test/unit-tests/stubs.ts index a0df7cf8d9..8fa2535f47 100644 --- a/lib/common/test/unit-tests/stubs.ts +++ b/lib/common/test/unit-tests/stubs.ts @@ -58,7 +58,7 @@ export class ErrorsStub implements IErrors { printCallStack: boolean = false; fail(formatStr: string, ...args: any[]): never; - fail(opts: { formatStr?: string; errorCode?: number; suppressCommandHelp?: boolean }, ...args: any[]): never; + fail(opts: IFailOptions, ...args: any[]): never; fail(...args: any[]): never { if (_.isObject(args) && (args).formatStr) { @@ -68,8 +68,12 @@ export class ErrorsStub implements IErrors { throw new Error(util.format.apply(null, args)); } - failWithoutHelp(message: string, ...args: any[]): never { - throw new Error(message); + failWithoutHelp(opts: string | IFailOptions, ...args: any[]): never { + return this.fail(opts, args); + } + + failWithHelp(opts: string | IFailOptions, ...args: any[]): never { + return this.fail(opts, args); } async beginCommand(action: () => Promise, printHelpCommand: () => Promise): Promise { diff --git a/lib/common/test/unit-tests/xcode-select-service.ts b/lib/common/test/unit-tests/xcode-select-service.ts index a44d878d51..c54bbff223 100644 --- a/lib/common/test/unit-tests/xcode-select-service.ts +++ b/lib/common/test/unit-tests/xcode-select-service.ts @@ -23,7 +23,9 @@ function createTestInjector(config: { xcodeSelectStdout: string, isDarwin: boole } }); testInjector.register("errors", { - failWithoutHelp: (message: string, ...args: any[]): void => { executionStopped = true; } + failWithHelp: (): void => { executionStopped = true; }, + failWithoutHelp: (): void => { executionStopped = true; }, + fail: (): void => { executionStopped = true; } }); testInjector.register("hostInfo", { diff --git a/lib/common/yok.ts b/lib/common/yok.ts index 556e267c7f..efcb5e0878 100644 --- a/lib/common/yok.ts +++ b/lib/common/yok.ts @@ -258,7 +258,7 @@ export class Yok implements IInjector { // there isn't a valid command or default with those arguments const errors = $injector.resolve("errors"); - errors.fail(ERROR_NO_VALID_SUBCOMMAND_FORMAT, commandName); + errors.failWithHelp(ERROR_NO_VALID_SUBCOMMAND_FORMAT, commandName); } return true; diff --git a/lib/controllers/debug-controller.ts b/lib/controllers/debug-controller.ts index 6b079294d8..0b86d66c2b 100644 --- a/lib/controllers/debug-controller.ts +++ b/lib/controllers/debug-controller.ts @@ -28,11 +28,11 @@ export class DebugController extends EventEmitter implements IDebugController { const device = this.$devicesService.getDeviceByIdentifier(debugData.deviceIdentifier); if (!device) { - this.$errors.failWithoutHelp(`Cannot find device with identifier ${debugData.deviceIdentifier}.`); + this.$errors.fail(`Cannot find device with identifier ${debugData.deviceIdentifier}.`); } if (device.deviceInfo.status !== CONNECTED_STATUS) { - this.$errors.failWithoutHelp(`The device with identifier ${debugData.deviceIdentifier} is unreachable. Make sure it is Trusted and try again.`); + this.$errors.fail(`The device with identifier ${debugData.deviceIdentifier} is unreachable. Make sure it is Trusted and try again.`); } await this.$analyticsService.trackEventActionInGoogleAnalytics({ @@ -43,12 +43,12 @@ export class DebugController extends EventEmitter implements IDebugController { }); if (!(await device.applicationManager.isApplicationInstalled(debugData.applicationIdentifier))) { - this.$errors.failWithoutHelp(`The application ${debugData.applicationIdentifier} is not installed on device with identifier ${debugData.deviceIdentifier}.`); + this.$errors.fail(`The application ${debugData.applicationIdentifier} is not installed on device with identifier ${debugData.deviceIdentifier}.`); } const debugService = this.getDeviceDebugService(device); if (!debugService) { - this.$errors.failWithoutHelp(`Unsupported device OS: ${device.deviceInfo.platform}. You can debug your applications only on iOS or Android.`); + this.$errors.fail(`Unsupported device OS: ${device.deviceInfo.platform}. You can debug your applications only on iOS or Android.`); } const debugOptions: IDebugOptions = _.cloneDeep(options); @@ -77,12 +77,12 @@ export class DebugController extends EventEmitter implements IDebugController { if (currentDeviceDescriptor) { currentDeviceDescriptor.debuggingEnabled = false; } else { - this.$errors.failWithoutHelp(`Couldn't disable debugging for ${deviceIdentifier}`); + this.$errors.fail(`Couldn't disable debugging for ${deviceIdentifier}`); } const currentDevice = this.$devicesService.getDeviceByIdentifier(currentDeviceDescriptor.identifier); if (!currentDevice) { - this.$errors.failWithoutHelp(`Couldn't disable debugging for ${deviceIdentifier}. Could not find device.`); + this.$errors.fail(`Couldn't disable debugging for ${deviceIdentifier}. Could not find device.`); } await this.stopDebug(currentDevice.deviceInfo.identifier); @@ -118,7 +118,7 @@ export class DebugController extends EventEmitter implements IDebugController { public async enableDebuggingCoreWithoutWaitingCurrentAction(projectDir: string, deviceIdentifier: string, debugOptions: IDebugOptions): Promise { const deviceDescriptor = this.getDeviceDescriptor(projectDir, deviceIdentifier); if (!deviceDescriptor) { - this.$errors.failWithoutHelp(`Couldn't enable debugging for ${deviceIdentifier}`); + this.$errors.fail(`Couldn't enable debugging for ${deviceIdentifier}`); } deviceDescriptor.debuggingEnabled = true; @@ -184,7 +184,7 @@ export class DebugController extends EventEmitter implements IDebugController { } else if (this.$mobileHelper.isAndroidPlatform(devicePlatform)) { this._platformDebugServices[device.deviceInfo.identifier] = this.$injector.resolve("androidDeviceDebugService", { device }); } else { - this.$errors.failWithoutHelp(DebugCommandErrors.UNSUPPORTED_DEVICE_OS_FOR_DEBUGGING); + this.$errors.fail(DebugCommandErrors.UNSUPPORTED_DEVICE_OS_FOR_DEBUGGING); } this.attachConnectionErrorHandlers(this._platformDebugServices[device.deviceInfo.identifier]); diff --git a/lib/controllers/migrate-controller.ts b/lib/controllers/migrate-controller.ts index 838eeffb68..c374515ae9 100644 --- a/lib/controllers/migrate-controller.ts +++ b/lib/controllers/migrate-controller.ts @@ -140,7 +140,7 @@ Running this command will ${MigrateController.COMMON_MIGRATE_MESSAGE}`; await this.migrateDependencies(projectData, platforms, allowInvalidVersions); } catch (error) { this.restoreBackup(MigrateController.folders, backupDir, projectData.projectDir); - this.$errors.failWithoutHelp(`${MigrateController.migrateFailMessage} The error is: ${error}`); + this.$errors.fail(`${MigrateController.migrateFailMessage} The error is: ${error}`); } this.$logger.info(MigrateController.MIGRATE_FINISH_MESSAGE); @@ -192,7 +192,7 @@ Running this command will ${MigrateController.COMMON_MIGRATE_MESSAGE}`; public async validate({ projectDir, platforms, allowInvalidVersions = true }: IMigrationData): Promise { const shouldMigrate = await this.shouldMigrate({ projectDir, platforms, allowInvalidVersions }); if (shouldMigrate) { - this.$errors.failWithoutHelp(MigrateController.UNABLE_TO_MIGRATE_APP_ERROR); + this.$errors.fail(MigrateController.UNABLE_TO_MIGRATE_APP_ERROR); } } @@ -318,7 +318,7 @@ Running this command will ${MigrateController.COMMON_MIGRATE_MESSAGE}`; if (dependency.replaceWith) { const replacementDep = _.find(this.migrationDependencies, migrationPackage => migrationPackage.packageName === dependency.replaceWith); if (!replacementDep) { - this.$errors.failWithoutHelp("Failed to find replacement dependency."); + this.$errors.fail("Failed to find replacement dependency."); } this.$logger.info(`Replacing '${dependency.packageName}' with '${replacementDep.packageName}'.`); diff --git a/lib/controllers/platform-controller.ts b/lib/controllers/platform-controller.ts index b8dbb690c6..bd08ba90f7 100644 --- a/lib/controllers/platform-controller.ts +++ b/lib/controllers/platform-controller.ts @@ -14,7 +14,7 @@ export class PlatformController implements IPlatformController { ) { } public async addPlatform(addPlatformData: IAddPlatformData): Promise { - const [ platform, version ] = addPlatformData.platform.toLowerCase().split("@"); + const [platform, version] = addPlatformData.platform.toLowerCase().split("@"); const projectData = this.$projectDataService.getProjectData(addPlatformData.projectDir); const platformData = this.$platformsDataService.getPlatformData(platform, projectData); @@ -34,7 +34,7 @@ export class PlatformController implements IPlatformController { } public async addPlatformIfNeeded(addPlatformData: IAddPlatformData): Promise { - const [ platform ] = addPlatformData.platform.toLowerCase().split("@"); + const [platform] = addPlatformData.platform.toLowerCase().split("@"); const projectData = this.$projectDataService.getProjectData(addPlatformData.projectDir); const platformData = this.$platformsDataService.getPlatformData(platform, projectData); diff --git a/lib/controllers/preview-app-controller.ts b/lib/controllers/preview-app-controller.ts index b53ca164e3..447e86f429 100644 --- a/lib/controllers/preview-app-controller.ts +++ b/lib/controllers/preview-app-controller.ts @@ -59,7 +59,7 @@ export class PreviewAppController extends EventEmitter implements IPreviewAppCon await this.$previewSdkService.initialize(data.projectDir, async (device: Device) => { try { if (!device) { - this.$errors.failWithoutHelp("Sending initial preview files without a specified device is not supported."); + this.$errors.fail("Sending initial preview files without a specified device is not supported."); } if (this.deviceInitializationPromise[device.id]) { diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index d6cc35912e..dd15b5a9e3 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -247,7 +247,7 @@ export class RunController extends EventEmitter implements IRunController { await this.$pluginsService.ensureAllDependenciesAreInstalled(projectData); } catch (err) { this.$logger.trace(err); - this.$errors.failWithoutHelp(`Unable to install dependencies. Make sure your package.json is valid and all dependencies are correct. Error is: ${err.message}`); + this.$errors.fail(`Unable to install dependencies. Make sure your package.json is valid and all dependencies are correct. Error is: ${err.message}`); } } diff --git a/lib/device-path-provider.ts b/lib/device-path-provider.ts index b80ec0fe90..f361a55e65 100644 --- a/lib/device-path-provider.ts +++ b/lib/device-path-provider.ts @@ -15,7 +15,7 @@ export class DevicePathProvider implements IDevicePathProvider { projectRoot = device.isEmulator ? await this.$iOSSimResolver.iOSSim.getApplicationPath(device.deviceInfo.identifier, options.appIdentifier) : LiveSyncPaths.IOS_DEVICE_PROJECT_ROOT_PATH; if (!projectRoot) { - this.$errors.failWithoutHelp("Unable to get application path on device."); + this.$errors.fail("Unable to get application path on device."); } if (!options.getDirname) { diff --git a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts index d561b6cf16..24e7d9481d 100644 --- a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts +++ b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts @@ -25,7 +25,7 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu const cacheKey = `${device.deviceInfo.identifier}-${appId}`; const existingServer = this.deviceTcpServers[cacheKey]; if (existingServer) { - this.$errors.failWithoutHelp(`TCP socket proxy is already running for device '${device.deviceInfo.identifier}' and app '${appId}'`); + this.$errors.fail(`TCP socket proxy is already running for device '${device.deviceInfo.identifier}' and app '${appId}'`); } this.$logger.info("\nSetting up proxy...\nPress Ctrl + C to terminate, or disconnect.\n"); @@ -96,7 +96,7 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu const cacheKey = `${device.deviceInfo.identifier}-${appId}`; const existingServer = this.deviceWebServers[cacheKey]; if (existingServer) { - this.$errors.failWithoutHelp(`Web socket proxy is already running for device '${device.deviceInfo.identifier}' and app '${appId}'`); + this.$errors.fail(`Web socket proxy is already running for device '${device.deviceInfo.identifier}' and app '${appId}'`); } // NOTE: We will try to provide command line options to select ports, at least on the localhost. diff --git a/lib/device-sockets/ios/socket-request-executor.ts b/lib/device-sockets/ios/socket-request-executor.ts index b593815c83..28750b70c7 100644 --- a/lib/device-sockets/ios/socket-request-executor.ts +++ b/lib/device-sockets/ios/socket-request-executor.ts @@ -15,7 +15,7 @@ export class IOSSocketRequestExecutor implements IiOSSocketRequestExecutor { await this.$iOSNotificationService.postNotification(deviceIdentifier, this.$iOSNotification.getAttachRequest(projectId, deviceIdentifier)); await readyForAttachPromise; } catch (e) { - this.$errors.failWithoutHelp(`The application ${projectId} does not appear to be running on ${deviceIdentifier} or is not built with debugging enabled. Try starting the application manually.`); + this.$errors.fail(`The application ${projectId} does not appear to be running on ${deviceIdentifier} or is not built with debugging enabled. Try starting the application manually.`); } } } diff --git a/lib/helpers/android-bundle-validator-helper.ts b/lib/helpers/android-bundle-validator-helper.ts index fbcbd3698b..66a173113c 100644 --- a/lib/helpers/android-bundle-validator-helper.ts +++ b/lib/helpers/android-bundle-validator-helper.ts @@ -9,12 +9,12 @@ export class AndroidBundleValidatorHelper extends VersionValidatorHelper impleme protected $errors: IErrors, protected $options: IOptions, protected $projectDataService: IProjectDataService) { - super(); + super(); } public validateNoAab(): void { if (this.$options.aab) { - this.$errors.fail(AndroidBundleValidatorMessages.AAB_NOT_SUPPORTED_BY_COMMNAND_MESSAGE); + this.$errors.failWithHelp(AndroidBundleValidatorMessages.AAB_NOT_SUPPORTED_BY_COMMNAND_MESSAGE); } } @@ -27,7 +27,7 @@ export class AndroidBundleValidatorHelper extends VersionValidatorHelper impleme this.isVersionLowerThan(androidRuntimeVersion, AndroidBundleValidatorHelper.MIN_RUNTIME_VERSION); if (shouldThrowError) { - this.$errors.failWithoutHelp(util.format(AndroidBundleValidatorMessages.NOT_SUPPORTED_RUNTIME_VERSION, AndroidBundleValidatorHelper.MIN_RUNTIME_VERSION)); + this.$errors.fail(util.format(AndroidBundleValidatorMessages.NOT_SUPPORTED_RUNTIME_VERSION, AndroidBundleValidatorHelper.MIN_RUNTIME_VERSION)); } } } diff --git a/lib/helpers/livesync-command-helper.ts b/lib/helpers/livesync-command-helper.ts index f895783f2f..4377b6b1f8 100644 --- a/lib/helpers/livesync-command-helper.ts +++ b/lib/helpers/livesync-command-helper.ts @@ -136,9 +136,9 @@ export class LiveSyncCommandHelper implements ILiveSyncCommandHelper { private async executeLiveSyncOperationCore(devices: Mobile.IDevice[], platform: string, additionalOptions?: ILiveSyncCommandHelperAdditionalOptions): Promise<{ liveSyncInfo: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceDescriptor[] }> { if (!devices || !devices.length) { if (platform) { - this.$errors.failWithoutHelp("Unable to find applicable devices to execute operation. Ensure connected devices are trusted and try again."); + this.$errors.fail("Unable to find applicable devices to execute operation. Ensure connected devices are trusted and try again."); } else { - this.$errors.failWithoutHelp("Unable to find applicable devices to execute operation and unable to start emulator when platform is not specified."); + this.$errors.fail("Unable to find applicable devices to execute operation and unable to start emulator when platform is not specified."); } } diff --git a/lib/helpers/network-connectivity-validator.ts b/lib/helpers/network-connectivity-validator.ts index 3e82721cb2..db3584a619 100644 --- a/lib/helpers/network-connectivity-validator.ts +++ b/lib/helpers/network-connectivity-validator.ts @@ -11,7 +11,7 @@ export class NetworkConnectivityValidator implements INetworkConnectivityValidat public async validate(): Promise { const isConnected = await this.isConnected(); if (!isConnected) { - this.$errors.failWithoutHelp(NetworkConnectivityValidator.NO_INTERNET_ERROR_MESSAGE); + this.$errors.fail(NetworkConnectivityValidator.NO_INTERNET_ERROR_MESSAGE); } } diff --git a/lib/helpers/platform-command-helper.ts b/lib/helpers/platform-command-helper.ts index 18e48a280b..0352fca6e8 100644 --- a/lib/helpers/platform-command-helper.ts +++ b/lib/helpers/platform-command-helper.ts @@ -30,7 +30,7 @@ export class PlatformCommandHelper implements IPlatformCommandHelper { const isPlatformAdded = this.isPlatformAdded(platform, platformPath, projectData); if (isPlatformAdded) { - this.$errors.failWithoutHelp(`Platform ${platform} already added`); + this.$errors.fail(`Platform ${platform} already added`); } await this.$platformController.addPlatform({ @@ -75,7 +75,7 @@ export class PlatformCommandHelper implements IPlatformCommandHelper { if (errorMessage) { this.$logger.error(errorMessage); } - this.$errors.failWithoutHelp(err.message); + this.$errors.fail(err.message); } } } @@ -169,7 +169,7 @@ export class PlatformCommandHelper implements IPlatformCommandHelper { this.$errors.fail(`Your current version: ${currentVersion} is higher than the one you're trying to install ${newVersion}.`); } } else { - this.$errors.failWithoutHelp("Native Platform cannot be updated."); + this.$errors.fail("Native Platform cannot be updated."); } } diff --git a/lib/node-package-manager.ts b/lib/node-package-manager.ts index beb17ae665..6befe25009 100644 --- a/lib/node-package-manager.ts +++ b/lib/node-package-manager.ts @@ -95,7 +95,7 @@ export class NodePackageManager extends BasePackageManager { try { viewResult = await this.$childProcess.exec(`npm view ${packageName} ${flags}`); } catch (e) { - this.$errors.failWithoutHelp(e.message); + this.$errors.fail(e.message); } return JSON.parse(viewResult); } diff --git a/lib/options.ts b/lib/options.ts index 4c9d1fa83f..8893b85e4f 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -32,7 +32,7 @@ export class Options { // Check if the user has explicitly provide --hmr and --release options from command line if (this.initialArgv.release && this.initialArgv.hmr) { - this.$errors.failWithoutHelp("The options --release and --hmr cannot be used simultaneously."); + this.$errors.fail("The options --release and --hmr cannot be used simultaneously."); } if (this.argv.hmr) { @@ -47,7 +47,6 @@ export class Options { } constructor(private $errors: IErrors, - private $staticConfig: Config.IStaticConfig, private $settingsService: ISettingsService) { this.options = _.extend({}, this.commonOptions, this.globalOptions); @@ -176,18 +175,18 @@ export class Options { if (!_.includes(this.optionsWhiteList, optionName)) { if (!this.isOptionSupported(optionName)) { - this.$errors.failWithoutHelp(`The option '${originalOptionName}' is not supported. To see command's options, use '$ ${this.$staticConfig.CLIENT_NAME.toLowerCase()} help ${process.argv[2]}'. To see all commands use '$ ${this.$staticConfig.CLIENT_NAME.toLowerCase()} help'.`); + this.$errors.failWithHelp(`The option '${originalOptionName}' is not supported.`); } const optionType = this.getOptionType(optionName), optionValue = parsed[optionName]; if (_.isArray(optionValue) && optionType !== OptionType.Array) { - this.$errors.fail("You have set the %s option multiple times. Check the correct command syntax below and try again.", originalOptionName); + this.$errors.failWithHelp("The '%s' option requires a single value.", originalOptionName); } else if (optionType === OptionType.String && helpers.isNullOrWhitespace(optionValue)) { - this.$errors.failWithoutHelp("The option '%s' requires non-empty value.", originalOptionName); + this.$errors.failWithHelp("The option '%s' requires non-empty value.", originalOptionName); } else if (optionType === OptionType.Array && optionValue.length === 0) { - this.$errors.failWithoutHelp(`The option '${originalOptionName}' requires one or more values, separated by a space.`); + this.$errors.failWithHelp(`The option '${originalOptionName}' requires one or more values, separated by a space.`); } } }); diff --git a/lib/project-data.ts b/lib/project-data.ts index 935d1a497e..cd8ac33e6a 100644 --- a/lib/project-data.ts +++ b/lib/project-data.ts @@ -104,7 +104,7 @@ export class ProjectData implements IProjectData { packageJsonData = parseJson(packageJsonContent); nsData = packageJsonData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE]; } catch (err) { - this.$errors.failWithoutHelp(`The project file ${this.projectFilePath} is corrupted. ${EOL}` + + this.$errors.fail(`The project file ${this.projectFilePath} is corrupted. ${EOL}` + `Consider restoring an earlier version from your source control or backup.${EOL}` + `Additional technical info: ${err.toString()}`); } @@ -112,7 +112,7 @@ export class ProjectData implements IProjectData { try { nsConfig = nsconfigContent ? parseJson(nsconfigContent) : null; } catch (err) { - this.$errors.failWithoutHelp(`The NativeScript configuration file ${constants.CONFIG_NS_FILE_NAME} is corrupted. ${EOL}` + + this.$errors.fail(`The NativeScript configuration file ${constants.CONFIG_NS_FILE_NAME} is corrupted. ${EOL}` + `Consider restoring an earlier version from your source control or backup.${EOL}` + `Additional technical info: ${err.toString()}`); } diff --git a/lib/resolvers/livesync-service-resolver.ts b/lib/resolvers/livesync-service-resolver.ts index d6eebdef7d..82a93079f9 100644 --- a/lib/resolvers/livesync-service-resolver.ts +++ b/lib/resolvers/livesync-service-resolver.ts @@ -12,7 +12,7 @@ export class LiveSyncServiceResolver implements ILiveSyncServiceResolver { return this.$injector.resolve("androidLiveSyncService"); } - this.$errors.failWithoutHelp(`Invalid platform ${platform}. Supported platforms are: ${this.$mobileHelper.platformNames.join(", ")}`); + this.$errors.fail(`Invalid platform ${platform}. Supported platforms are: ${this.$mobileHelper.platformNames.join(", ")}`); } } $injector.register("liveSyncServiceResolver", LiveSyncServiceResolver); diff --git a/lib/services/android-device-debug-service.ts b/lib/services/android-device-debug-service.ts index 863d2974fa..4c52c56291 100644 --- a/lib/services/android-device-debug-service.ts +++ b/lib/services/android-device-debug-service.ts @@ -110,7 +110,7 @@ export class AndroidDeviceDebugService extends DebugServiceBase implements IDevi // TODO: extract this logic outside the debug service private async validateRunningApp(deviceId: string, packageName: string): Promise { if (!(await this.isAppRunning(packageName, deviceId))) { - this.$errors.failWithoutHelp(`The application ${packageName} does not appear to be running on ${deviceId} or is not built with debugging enabled. Try starting the application manually.`); + this.$errors.fail(`The application ${packageName} does not appear to be running on ${deviceId} or is not built with debugging enabled. Try starting the application manually.`); } } diff --git a/lib/services/android-plugin-build-service.ts b/lib/services/android-plugin-build-service.ts index ec816fd440..1ee5cdfac5 100644 --- a/lib/services/android-plugin-build-service.ts +++ b/lib/services/android-plugin-build-service.ts @@ -253,7 +253,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { try { androidManifestContent = this.$fs.readText(manifestFilePath); } catch (err) { - this.$errors.failWithoutHelp(`Failed to fs.readFileSync the manifest file located at ${manifestFilePath}. Error is: ${err.toString()}`); + this.$errors.fail(`Failed to fs.readFileSync the manifest file located at ${manifestFilePath}. Error is: ${err.toString()}`); } updatedManifestContent = await this.updateManifestContent(androidManifestContent, defaultPackageName); @@ -265,7 +265,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { try { this.$fs.writeFile(pathToTempAndroidManifest, updatedManifestContent); } catch (e) { - this.$errors.failWithoutHelp(`Failed to write the updated AndroidManifest in the new location - ${pathToTempAndroidManifest}. Error is: ${e.toString()}`); + this.$errors.fail(`Failed to write the updated AndroidManifest in the new location - ${pathToTempAndroidManifest}. Error is: ${e.toString()}`); } } @@ -396,10 +396,10 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { this.$fs.copyFile(pathToBuiltAar, path.join(aarOutputDir, `${shortPluginName}.aar`)); } } catch (e) { - this.$errors.failWithoutHelp(`Failed to copy built aar to destination. ${e.message}`); + this.$errors.fail(`Failed to copy built aar to destination. ${e.message}`); } } else { - this.$errors.failWithoutHelp(`No built aar found at ${pathToBuiltAar}`); + this.$errors.fail(`No built aar found at ${pathToBuiltAar}`); } } @@ -417,7 +417,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { try { includeGradleFileContent = this.$fs.readFile(includeGradleFilePath).toString(); } catch (err) { - this.$errors.failWithoutHelp(`Failed to fs.readFileSync the include.gradle file located at ${includeGradleFilePath}. Error is: ${err.toString()}`); + this.$errors.fail(`Failed to fs.readFileSync the include.gradle file located at ${includeGradleFilePath}. Error is: ${err.toString()}`); } const productFlavorsScope = this.getScope("productFlavors", includeGradleFileContent); @@ -428,7 +428,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { return true; } catch (e) { - this.$errors.failWithoutHelp(`Failed to write the updated include.gradle ` + + this.$errors.fail(`Failed to write the updated include.gradle ` + `in - ${includeGradleFilePath}. Error is: ${e.toString()}`); } } @@ -461,13 +461,13 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { try { await this.$childProcess.spawnFromEvent(gradlew, localArgs, "close", { cwd: pluginBuildSettings.pluginDir, stdio: "inherit" }); } catch (err) { - this.$errors.failWithoutHelp(`Failed to build plugin ${pluginBuildSettings.pluginName} : \n${err}`); + this.$errors.fail(`Failed to build plugin ${pluginBuildSettings.pluginName} : \n${err}`); } } private validateOptions(options: IPluginBuildOptions): void { if (!options) { - this.$errors.failWithoutHelp("Android plugin cannot be built without passing an 'options' object."); + this.$errors.fail("Android plugin cannot be built without passing an 'options' object."); } if (!options.pluginName) { @@ -479,7 +479,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { } if (!options.tempPluginDirPath) { - this.$errors.failWithoutHelp("Android plugin cannot be built without passing the path to a directory where the temporary project should be built."); + this.$errors.fail("Android plugin cannot be built without passing the path to a directory where the temporary project should be built."); } this.validatePlatformsAndroidDirPathOption(options); @@ -487,11 +487,11 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { private validatePlatformsAndroidDirPathOption(options: IPluginBuildOptions): void { if (!options) { - this.$errors.failWithoutHelp("Android plugin cannot be built without passing an 'options' object."); + this.$errors.fail("Android plugin cannot be built without passing an 'options' object."); } if (!options.platformsAndroidDirPath) { - this.$errors.failWithoutHelp("Android plugin cannot be built without passing the path to the platforms/android dir."); + this.$errors.fail("Android plugin cannot be built without passing the path to the platforms/android dir."); } } diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index cccfa2d47f..187ef80a6f 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -130,7 +130,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject public async createProject(frameworkDir: string, frameworkVersion: string, projectData: IProjectData): Promise { if (semver.lt(frameworkVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) { - this.$errors.failWithoutHelp(`The NativeScript CLI requires Android runtime ${AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE} or later to work properly.`); + this.$errors.fail(`The NativeScript CLI requires Android runtime ${AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE} or later to work properly.`); } this.$fs.ensureDirectoryExists(this.getPlatformData(projectData).projectRoot); diff --git a/lib/services/android-resources-migration-service.ts b/lib/services/android-resources-migration-service.ts index 6167154e53..bb75d80261 100644 --- a/lib/services/android-resources-migration-service.ts +++ b/lib/services/android-resources-migration-service.ts @@ -36,7 +36,7 @@ export class AndroidResourcesMigrationService implements IAndroidResourcesMigrat this.$logger.trace(err); this.$logger.info(`Failed to update resources.${EOL} Backup of original content is inside "${appResourcesBackup}".${EOL}If "${originalAppResources} is missing copy from backup folder."`); } finally { - this.$errors.failWithoutHelp(error.message); + this.$errors.fail(error.message); } } } diff --git a/lib/services/android/gradle-command-service.ts b/lib/services/android/gradle-command-service.ts index 07e398450b..5e2ab564e6 100644 --- a/lib/services/android/gradle-command-service.ts +++ b/lib/services/android/gradle-command-service.ts @@ -24,7 +24,7 @@ export class GradleCommandService implements IGradleCommandService { return result; } catch (err) { - this.$errors.failWithoutHelp(err.message); + this.$errors.fail(err.message); } } } diff --git a/lib/services/apple-portal/apple-portal-application-service.ts b/lib/services/apple-portal/apple-portal-application-service.ts index 791e420bb1..c3a55f7662 100644 --- a/lib/services/apple-portal/apple-portal-application-service.ts +++ b/lib/services/apple-portal/apple-portal-application-service.ts @@ -39,13 +39,13 @@ export class ApplePortalApplicationService implements IApplePortalApplicationSer public async getApplicationByBundleId(credentials: ICredentials, bundleId: string): Promise { const applications = await this.getApplications(credentials); if (!applications || !applications.length) { - this.$errors.failWithoutHelp(`Cannot find any registered applications for Apple ID ${credentials.username} in iTunes Connect.`); + this.$errors.fail(`Cannot find any registered applications for Apple ID ${credentials.username} in iTunes Connect.`); } const application = _.find(applications, app => app.bundleId === bundleId); if (!application) { - this.$errors.failWithoutHelp(`Cannot find registered applications that match the specified identifier ${bundleId} in iTunes Connect.`); + this.$errors.fail(`Cannot find registered applications that match the specified identifier ${bundleId} in iTunes Connect.`); } return application; diff --git a/lib/services/build-artefacts-service.ts b/lib/services/build-artefacts-service.ts index a05f083d82..0d832d4521 100644 --- a/lib/services/build-artefacts-service.ts +++ b/lib/services/build-artefacts-service.ts @@ -13,7 +13,7 @@ export class BuildArtefactsService implements IBuildArtefactsService { const packageFile = applicationPackage.packageName; if (!packageFile || !this.$fs.exists(packageFile)) { - this.$errors.failWithoutHelp(`Unable to find built application. Try 'tns build ${platformData.platformNameLowerCase}'.`); + this.$errors.fail(`Unable to find built application. Try 'tns build ${platformData.platformNameLowerCase}'.`); } return packageFile; diff --git a/lib/services/cocoapods-service.ts b/lib/services/cocoapods-service.ts index 129941d913..e150222553 100644 --- a/lib/services/cocoapods-service.ts +++ b/lib/services/cocoapods-service.ts @@ -35,7 +35,7 @@ export class CocoaPodsService implements ICocoaPodsService { await this.$childProcess.exec("which pod"); await this.$childProcess.exec("which xcodeproj"); } catch (e) { - this.$errors.failWithoutHelp("CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again."); + this.$errors.fail("CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again."); } await this.$xcprojService.verifyXcproj({ shouldFail: true }); @@ -46,7 +46,7 @@ export class CocoaPodsService implements ICocoaPodsService { const podInstallResult = await this.$childProcess.spawnFromEvent(podTool, ["install"], "close", { cwd: projectRoot, stdio: ['pipe', process.stdout, process.stdout] }, { throwError: false }); if (podInstallResult.exitCode !== 0) { - this.$errors.failWithoutHelp(`'${podTool} install' command failed.${podInstallResult.stderr ? " Error is: " + podInstallResult.stderr : ""}`); + this.$errors.fail(`'${podTool} install' command failed.${podInstallResult.stderr ? " Error is: " + podInstallResult.stderr : ""}`); } if ((await this.$xcprojService.getXcprojInfo()).shouldUseXcproj) { diff --git a/lib/services/initialize-service.ts b/lib/services/initialize-service.ts index 117da1b4c1..1fe0356b9d 100644 --- a/lib/services/initialize-service.ts +++ b/lib/services/initialize-service.ts @@ -1,4 +1,5 @@ import { EOL } from "os"; +import { LoggerLevel } from "../constants"; export class InitializeService implements IInitializeService { // NOTE: Do not inject anything here, use $injector.resolve in the code @@ -11,7 +12,9 @@ export class InitializeService implements IInitializeService { if (initOpts.loggerOptions) { $logger.initialize(initOpts.loggerOptions); } else { - $logger.initializeCliLogger(); + const $options = this.$injector.resolve("options"); + const loggerLevel = $options.log && LoggerLevel[$options.log.toUpperCase() as keyof typeof LoggerLevel]; + $logger.initializeCliLogger({ level: loggerLevel }); } if (initOpts.settingsServiceOptions) { diff --git a/lib/services/ios-device-debug-service.ts b/lib/services/ios-device-debug-service.ts index f2102dc155..81db1cc943 100644 --- a/lib/services/ios-device-debug-service.ts +++ b/lib/services/ios-device-debug-service.ts @@ -46,11 +46,11 @@ export class IOSDeviceDebugService extends DebugServiceBase implements IDeviceDe private validateOptions(debugOptions: IDebugOptions) { if (!this.$hostInfo.isWindows && !this.$hostInfo.isDarwin) { - this.$errors.failWithoutHelp(`Debugging on iOS devices is not supported for ${platform()} yet.`); + this.$errors.fail(`Debugging on iOS devices is not supported for ${platform()} yet.`); } if (debugOptions.debugBrk && debugOptions.start) { - this.$errors.failWithoutHelp("Expected exactly one of the --debug-brk or --start options."); + this.$errors.fail("Expected exactly one of the --debug-brk or --start options."); } } diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 8a0d737068..c308810f32 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -104,17 +104,17 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ public async validateOptions(projectId: string, provision: true | string, teamId: true | string): Promise { if (provision && teamId) { - this.$errors.failWithoutHelp("The options --provision and --teamId are mutually exclusive."); + this.$errors.fail("The options --provision and --teamId are mutually exclusive."); } if (provision === true) { await this.$iOSProvisionService.listProvisions(projectId); - this.$errors.failWithoutHelp("Please provide provisioning profile uuid or name with the --provision option."); + this.$errors.fail("Please provide provisioning profile uuid or name with the --provision option."); } if (teamId === true) { await this.$iOSProvisionService.listTeams(); - this.$errors.failWithoutHelp("Please provide team id or team name with the --teamId options."); + this.$errors.fail("Please provide team id or team name with the --teamId options."); } return true; @@ -619,14 +619,14 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ private validateFramework(libraryPath: string): void { const infoPlistPath = path.join(libraryPath, constants.INFO_PLIST_FILE_NAME); if (!this.$fs.exists(infoPlistPath)) { - this.$errors.failWithoutHelp("The bundle at %s does not contain an Info.plist file.", libraryPath); + this.$errors.fail("The bundle at %s does not contain an Info.plist file.", libraryPath); } const plistJson = this.$plistParser.parseFileSync(infoPlistPath); const packageType = plistJson["CFBundlePackageType"]; if (packageType !== "FMWK" && packageType !== "XFWK") { - this.$errors.failWithoutHelp("The bundle at %s does not appear to be a dynamic framework.", libraryPath); + this.$errors.fail("The bundle at %s does not appear to be a dynamic framework.", libraryPath); } } diff --git a/lib/services/ios/ios-signing-service.ts b/lib/services/ios/ios-signing-service.ts index 58ea06b2b0..6afdbbd266 100644 --- a/lib/services/ios/ios-signing-service.ts +++ b/lib/services/ios/ios-signing-service.ts @@ -103,7 +103,7 @@ export class IOSSigningService implements IiOSSigningService { const pickEnd = Date.now(); this.$logger.trace("Searched and " + (mobileprovision ? "found" : "failed to find ") + " matching provisioning profile. (" + (pickEnd - pickStart) + "ms.)"); if (!mobileprovision) { - this.$errors.failWithoutHelp("Failed to find mobile provision with UUID or Name: " + provision); + this.$errors.fail("Failed to find mobile provision with UUID or Name: " + provision); } const configuration = { team: mobileprovision.TeamIdentifier && mobileprovision.TeamIdentifier.length > 0 ? mobileprovision.TeamIdentifier[0] : undefined, @@ -147,7 +147,7 @@ export class IOSSigningService implements IiOSSigningService { this.$logger.warn("Found and using the following development team installed on your system: " + teams[0].name + " (" + teams[0].id + ")"); } else if (teams.length > 0) { if (!helpers.isInteractive()) { - this.$errors.failWithoutHelp(`Unable to determine default development team. Available development teams are: ${_.map(teams, team => team.id)}. Specify team in app/App_Resources/iOS/build.xcconfig file in the following way: DEVELOPMENT_TEAM = `); + this.$errors.fail(`Unable to determine default development team. Available development teams are: ${_.map(teams, team => team.id)}. Specify team in app/App_Resources/iOS/build.xcconfig file in the following way: DEVELOPMENT_TEAM = `); } const choices: string[] = []; diff --git a/lib/services/ios/xcodebuild-command-service.ts b/lib/services/ios/xcodebuild-command-service.ts index 172a19b873..d4dba962b0 100644 --- a/lib/services/ios/xcodebuild-command-service.ts +++ b/lib/services/ios/xcodebuild-command-service.ts @@ -22,7 +22,7 @@ export class XcodebuildCommandService implements IXcodebuildCommandService { return commandResult; } catch (err) { - this.$errors.failWithoutHelp(err.message); + this.$errors.fail(err.message); } } } diff --git a/lib/services/itmstransporter-service.ts b/lib/services/itmstransporter-service.ts index c129e9332f..8da333c6e8 100644 --- a/lib/services/itmstransporter-service.ts +++ b/lib/services/itmstransporter-service.ts @@ -48,7 +48,7 @@ export class ITMSTransporterService implements IITMSTransporterService { if (shouldExtractIpa) { if (!this.$fs.exists(ipaFilePath) || path.extname(ipaFilePath) !== ".ipa") { - this.$errors.failWithoutHelp(`Cannot use specified ipa file ${ipaFilePath}. File either does not exist or is not an ipa file.`); + this.$errors.fail(`Cannot use specified ipa file ${ipaFilePath}. File either does not exist or is not an ipa file.`); } this.$logger.trace("--ipa set - extracting .ipa file to get app's bundle identifier"); @@ -64,16 +64,16 @@ export class ITMSTransporterService implements IITMSTransporterService { allFiles = allFiles.filter(f => path.extname(f).toLowerCase() === ".app"); if (allFiles.length > 1) { - this.$errors.failWithoutHelp("In the .ipa the ITMSTransporter is uploading there is more than one .app file. We don't know which one to upload."); + this.$errors.fail("In the .ipa the ITMSTransporter is uploading there is more than one .app file. We don't know which one to upload."); } else if (allFiles.length <= 0) { - this.$errors.failWithoutHelp("In the .ipa the ITMSTransporter is uploading there must be at least one .app file."); + this.$errors.fail("In the .ipa the ITMSTransporter is uploading there must be at least one .app file."); } const appFile = path.join(payloadDir, allFiles[0]); const plistObject = await this.$plistParser.parseFile(path.join(appFile, INFO_PLIST_FILE_NAME)); const bundleId = plistObject && plistObject.CFBundleIdentifier; if (!bundleId) { - this.$errors.failWithoutHelp(`Unable to determine bundle identifier from ${ipaFilePath}.`); + this.$errors.fail(`Unable to determine bundle identifier from ${ipaFilePath}.`); } this.$logger.trace(`bundle identifier determined to be ${bundleId}`); @@ -91,7 +91,7 @@ export class ITMSTransporterService implements IITMSTransporterService { const itmsTransporterPath = path.join(loaderAppContentsPath, ITMSConstants.iTMSDirectoryName, "bin", ITMSConstants.iTMSExecutableName); if (!this.$fs.exists(itmsTransporterPath)) { - this.$errors.failWithoutHelp('iTMS Transporter not found on this machine - make sure your Xcode installation is not damaged.'); + this.$errors.fail('iTMS Transporter not found on this machine - make sure your Xcode installation is not damaged.'); } return itmsTransporterPath; diff --git a/lib/services/livesync/android-livesync-tool.ts b/lib/services/livesync/android-livesync-tool.ts index d55d010aec..f2ad2880c3 100644 --- a/lib/services/livesync/android-livesync-tool.ts +++ b/lib/services/livesync/android-livesync-tool.ts @@ -42,9 +42,9 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { private $logger: ILogger, private $mobileHelper: Mobile.IMobileHelper, private $injector: IInjector) { - this.operationPromises = Object.create(null); - this.socketError = null; - this.socketConnection = null; + this.operationPromises = Object.create(null); + this.socketError = null; + this.socketConnection = null; } public async connect(configuration: IAndroidLivesyncToolConfiguration): Promise { @@ -135,7 +135,7 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { public sendDoSyncOperation(options?: IDoSyncOperationOptions): Promise { options = _.assign({ doRefresh: true, timeout: SYNC_OPERATION_TIMEOUT }, options); - const { doRefresh , timeout, operationId } = options; + const { doRefresh, timeout, operationId } = options; const id = operationId || this.generateOperationIdentifier(); const operationPromise: Promise = new Promise((resolve, reject) => { if (!this.verifyActiveConnection(reject)) { @@ -190,36 +190,36 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { } private async sendFileHeader(filePath: string): Promise { - this.verifyActiveConnection(); - const filePathData = this.getFilePathData(filePath); - const stats = this.$fs.getFsStats(filePathData.filePath); - const fileContentLengthBytes = stats.size; - const fileContentLengthString = fileContentLengthBytes.toString(); - const fileContentLengthSize = Buffer.byteLength(fileContentLengthString); - const headerBuffer = Buffer.alloc(PROTOCOL_OPERATION_LENGTH_SIZE + - SIZE_BYTE_LENGTH + - filePathData.filePathLengthSize + - filePathData.filePathLengthBytes + - SIZE_BYTE_LENGTH + - fileContentLengthSize); - - if (filePathData.filePathLengthSize > 255) { - this.$errors.failWithoutHelp("File name size is longer that 255 digits."); - } else if (fileContentLengthSize > 255) { - this.$errors.failWithoutHelp("File name size is longer that 255 digits."); - } + this.verifyActiveConnection(); + const filePathData = this.getFilePathData(filePath); + const stats = this.$fs.getFsStats(filePathData.filePath); + const fileContentLengthBytes = stats.size; + const fileContentLengthString = fileContentLengthBytes.toString(); + const fileContentLengthSize = Buffer.byteLength(fileContentLengthString); + const headerBuffer = Buffer.alloc(PROTOCOL_OPERATION_LENGTH_SIZE + + SIZE_BYTE_LENGTH + + filePathData.filePathLengthSize + + filePathData.filePathLengthBytes + + SIZE_BYTE_LENGTH + + fileContentLengthSize); - let offset = 0; - offset += headerBuffer.write(AndroidLivesyncTool.CREATE_FILE_OPERATION.toString(), offset, PROTOCOL_OPERATION_LENGTH_SIZE); - offset = headerBuffer.writeUInt8(filePathData.filePathLengthSize, offset); - offset += headerBuffer.write(filePathData.filePathLengthString, offset, filePathData.filePathLengthSize); - offset += headerBuffer.write(filePathData.relativeFilePath, offset, filePathData.filePathLengthBytes); - offset = headerBuffer.writeUInt8(fileContentLengthSize, offset); - headerBuffer.write(fileContentLengthString, offset, fileContentLengthSize); - const hash = crypto.createHash("md5").update(headerBuffer).digest(); + if (filePathData.filePathLengthSize > 255) { + this.$errors.fail("File name size is longer that 255 digits."); + } else if (fileContentLengthSize > 255) { + this.$errors.fail("File name size is longer that 255 digits."); + } + + let offset = 0; + offset += headerBuffer.write(AndroidLivesyncTool.CREATE_FILE_OPERATION.toString(), offset, PROTOCOL_OPERATION_LENGTH_SIZE); + offset = headerBuffer.writeUInt8(filePathData.filePathLengthSize, offset); + offset += headerBuffer.write(filePathData.filePathLengthString, offset, filePathData.filePathLengthSize); + offset += headerBuffer.write(filePathData.relativeFilePath, offset, filePathData.filePathLengthBytes); + offset = headerBuffer.writeUInt8(fileContentLengthSize, offset); + headerBuffer.write(fileContentLengthString, offset, fileContentLengthSize); + const hash = crypto.createHash("md5").update(headerBuffer).digest(); - await this.writeToSocket(headerBuffer); - await this.writeToSocket(hash); + await this.writeToSocket(headerBuffer); + await this.writeToSocket(hash); } private sendFileContent(filePath: string): Promise { @@ -268,17 +268,17 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { } if (error && !rejectHandler) { - this.$errors.failWithoutHelp(error.toString()); + this.$errors.fail(error.toString()); } return true; } - private handleConnection({ socket, data }: { socket: ILiveSyncSocket, data: NodeBuffer | string }) { + private handleConnection({ socket, data }: { socket: ILiveSyncSocket, data: Buffer | string }) { this.socketConnection = socket; this.socketConnection.uid = this.generateOperationIdentifier(); - const versionLength = (data).readUInt8(0); + const versionLength = (data).readUInt8(0); const versionBuffer = data.slice(PROTOCOL_VERSION_LENGTH_SIZE, versionLength + PROTOCOL_VERSION_LENGTH_SIZE); const appIdentifierBuffer = data.slice(versionLength + PROTOCOL_VERSION_LENGTH_SIZE, data.length); @@ -287,7 +287,7 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { this.$logger.trace(`Handle socket connection for app identifier: ${appIdentifier} with protocol version: ${protocolVersion}.`); this.protocolVersion = protocolVersion; - this.socketConnection.on("data", (connectionData: NodeBuffer) => this.handleData(socket.uid, connectionData)); + this.socketConnection.on("data", (connectionData: Buffer) => this.handleData(socket.uid, connectionData)); this.socketConnection.on("close", (hasError: boolean) => this.handleSocketClose(socket.uid, hasError)); this.socketConnection.on("error", (err: Error) => { const error = new Error(`Socket Error:\n${err}`); @@ -299,7 +299,7 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { }); } - private connectEventuallyUntilTimeout(factory: () => ILiveSyncSocket, timeout: number): Promise<{socket: ILiveSyncSocket, data: NodeBuffer | string}> { + private connectEventuallyUntilTimeout(factory: () => ILiveSyncSocket, timeout: number): Promise<{ socket: ILiveSyncSocket, data: Buffer | string }> { return new Promise((resolve, reject) => { let lastKnownError: Error | string, isConnected = false; @@ -364,19 +364,19 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool { const errorMessage = infoBuffer.toString(); this.handleSocketError(socketId, errorMessage); } else if (reportType === AndroidLivesyncTool.OPERATION_END_REPORT) { - this.handleSyncEnd({data: infoBuffer, didRefresh: true}); + this.handleSyncEnd({ data: infoBuffer, didRefresh: true }); } else if (reportType === AndroidLivesyncTool.OPERATION_END_NO_REFRESH_REPORT_CODE) { - this.handleSyncEnd({data: infoBuffer, didRefresh: false}); + this.handleSyncEnd({ data: infoBuffer, didRefresh: false }); } } - private handleSyncEnd({data, didRefresh}: {data: any, didRefresh: boolean}) { + private handleSyncEnd({ data, didRefresh }: { data: any, didRefresh: boolean }) { const operationId = data.toString(); const promiseHandler = this.operationPromises[operationId]; if (promiseHandler) { clearTimeout(promiseHandler.timeoutId); - promiseHandler.resolve({operationId, didRefresh}); + promiseHandler.resolve({ operationId, didRefresh }); delete this.operationPromises[operationId]; } } diff --git a/lib/services/livesync/ios-device-livesync-service.ts b/lib/services/livesync/ios-device-livesync-service.ts index 69c250732a..a5274940d5 100644 --- a/lib/services/livesync/ios-device-livesync-service.ts +++ b/lib/services/livesync/ios-device-livesync-service.ts @@ -117,7 +117,7 @@ export class IOSDeviceLiveSyncService extends DeviceLiveSyncServiceBase implemen this.$logger.trace(`Socket error received: ${error}`); }); - this.socket.on("data", (data: NodeBuffer | string) => { + this.socket.on("data", (data: Buffer | string) => { this.$logger.trace(`Socket sent data: ${data.toString()}`); }); } diff --git a/lib/services/livesync/playground/preview-app-plugins-service.ts b/lib/services/livesync/playground/preview-app-plugins-service.ts index 490c10e42e..7a7bdd13f4 100644 --- a/lib/services/livesync/playground/preview-app-plugins-service.ts +++ b/lib/services/livesync/playground/preview-app-plugins-service.ts @@ -14,11 +14,11 @@ export class PreviewAppPluginsService implements IPreviewAppPluginsService { public getPluginsUsageWarnings(data: IPreviewAppLiveSyncData, device: Device): string[] { if (!device) { - this.$errors.failWithoutHelp("No device provided."); + this.$errors.fail("No device provided."); } if (!device.previewAppVersion) { - this.$errors.failWithoutHelp("No version of preview app provided."); + this.$errors.fail("No version of preview app provided."); } const devicePlugins = this.getDevicePlugins(device); diff --git a/lib/services/livesync/playground/preview-schema-service.ts b/lib/services/livesync/playground/preview-schema-service.ts index 45e8ccb89b..3fdd4d5e05 100644 --- a/lib/services/livesync/playground/preview-schema-service.ts +++ b/lib/services/livesync/playground/preview-schema-service.ts @@ -36,7 +36,7 @@ export class PreviewSchemaService implements IPreviewSchemaService { const result = this.previewSchemas[schemaName]; if (!result) { - this.$errors.failWithoutHelp(`Invalid schema. The valid schemas are ${_.keys(this.previewSchemas)}.`); + this.$errors.fail(`Invalid schema. The valid schemas are ${_.keys(this.previewSchemas)}.`); } return result; diff --git a/lib/services/log-parser-service.ts b/lib/services/log-parser-service.ts index 77616a9c99..97cf19c410 100644 --- a/lib/services/log-parser-service.ts +++ b/lib/services/log-parser-service.ts @@ -13,7 +13,7 @@ export class LogParserService extends EventEmitter implements ILogParserService public addParseRule(rule: ILogParseRule): void { if (this.parseRules[rule.name]) { - this.$errors.failWithoutHelp("Log parse rule already exists."); + this.$errors.fail("Log parse rule already exists."); } this.parseRules[rule.name] = rule; diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index d7bdadd84f..72a776e2a1 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -42,7 +42,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ public async checkEnvironmentRequirements(input: ICheckEnvironmentRequirementsInput): Promise { const { platform, projectDir, runtimeVersion } = input; const notConfiguredEnvOptions = input.notConfiguredEnvOptions || {}; - const options = input.options || { }; + const options = input.options || {}; let selectedOption = null; @@ -167,7 +167,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } } - private processManuallySetupIfNeeded(selectedOption: string, platform?: string) { + private processManuallySetupIfNeeded(selectedOption: string, platform?: string) { if (selectedOption === PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME) { this.processManuallySetup(platform); } @@ -176,7 +176,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ private async processSyncToPreviewAppIfNeeded(selectedOption: string, projectDir: string, options: IOptions) { if (selectedOption === PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_OPTION_NAME) { if (!projectDir) { - this.$errors.failWithoutHelp(`No project found. In order to sync to playground you need to go to project directory or specify --path option.`); + this.$errors.fail(`No project found. In order to sync to playground you need to go to project directory or specify --path option.`); } await this.$previewAppController.startPreview({ @@ -204,7 +204,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private fail(message: string): void { - this.$errors.fail({ formatStr: message, suppressCommandHelp: true, printOnStdout: true }); + this.$errors.fail({ formatStr: message, printOnStdout: true }); } private getNonInteractiveConsoleMessage(platform: string) { @@ -234,11 +234,11 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, `Select "Skip Step and Configure Manually" to disregard this option and install any required components manually.` ] : [ - `Select "Configure for Cloud Builds" to install the ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.`, - `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, - `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.`, - `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` - ]; + `Select "Configure for Cloud Builds" to install the ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.`, + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.`, + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` + ]; if (!options.hideSyncToPreviewAppOption) { choices.unshift(PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_MESSAGE); @@ -249,7 +249,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ return result; } - private async promptForChoice(opts: { infoMessage: string, choices: string[], }): Promise { + private async promptForChoice(opts: { infoMessage: string, choices: string[], }): Promise { this.$logger.info(opts.infoMessage); await this.$analyticsService.trackEventActionInGoogleAnalytics({ @@ -279,7 +279,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ const choices: string[] = []; if (this.$nativeScriptCloudExtensionService.isInstalled()) { choices.push(...[PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME]); + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME]); if (!options.hideCloudBuildOption) { choices.unshift(PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME); diff --git a/lib/services/platform/platform-validation-service.ts b/lib/services/platform/platform-validation-service.ts index 2ac7981c9d..4de3737a3c 100644 --- a/lib/services/platform/platform-validation-service.ts +++ b/lib/services/platform/platform-validation-service.ts @@ -26,7 +26,7 @@ export class PlatformValidationService implements IPlatformValidationService { public validatePlatform(platform: string, projectData: IProjectData): void { if (!platform) { - this.$errors.fail("No platform specified."); + this.$errors.failWithHelp("No platform specified."); } if (!this.isValidPlatform(platform, projectData)) { @@ -46,7 +46,7 @@ export class PlatformValidationService implements IPlatformValidationService { public async validateOptions(provision: true | string, teamId: true | string, projectData: IProjectData, platform?: string, aab?: boolean): Promise { if (platform && !this.$mobileHelper.isAndroidPlatform(platform) && aab) { - this.$errors.failWithoutHelp("The --aab option is supported only for the Android platform."); + this.$errors.fail("The --aab option is supported only for the Android platform."); } if (platform) { diff --git a/lib/services/plugins-service.ts b/lib/services/plugins-service.ts index 3cb7c89a93..5b3d156d6d 100644 --- a/lib/services/plugins-service.ts +++ b/lib/services/plugins-service.ts @@ -58,7 +58,7 @@ export class PluginsService implements IPluginsService { this.$logger.info(`Successfully installed plugin ${realNpmPackageJson.name}.`); } else { await this.$packageManager.uninstall(realNpmPackageJson.name, { save: true }, projectData.projectDir); - this.$errors.failWithoutHelp(`${plugin} is not a valid NativeScript plugin. Verify that the plugin package.json file contains a nativescript key and try again.`); + this.$errors.fail(`${plugin} is not a valid NativeScript plugin. Verify that the plugin package.json file contains a nativescript key and try again.`); } } diff --git a/lib/services/project-service.ts b/lib/services/project-service.ts index d9d1adb3b8..6cfbc8a481 100644 --- a/lib/services/project-service.ts +++ b/lib/services/project-service.ts @@ -25,7 +25,7 @@ export class ProjectService implements IProjectService { public async validateProjectName(opts: { projectName: string, force: boolean, pathToProject: string }): Promise { let projectName = opts.projectName; if (!projectName) { - this.$errors.fail("You must specify when creating a new project."); + this.$errors.failWithHelp("You must specify when creating a new project."); } projectName = await this.$projectNameService.ensureValidName(projectName, { force: opts.force }); @@ -140,7 +140,7 @@ export class ProjectService implements IProjectService { await this.$pacoteService.extractPackage(fullTemplateName, projectDir); break; default: - this.$errors.failWithoutHelp(format(constants.ProjectTemplateErrors.InvalidTemplateVersionStringFormat, templateData.templateName, templateData.templateVersion)); + this.$errors.fail(format(constants.ProjectTemplateErrors.InvalidTemplateVersionStringFormat, templateData.templateName, templateData.templateVersion)); break; } } @@ -189,7 +189,7 @@ export class ProjectService implements IProjectService { this.$logger.trace("New project package.json data: ", projectPackageJsonData); this.$fs.writeJson(projectPackageJsonPath, projectPackageJsonData); } else { - this.$errors.failWithoutHelp(`Couldn't find package.json data in installed template`); + this.$errors.fail(`Couldn't find package.json data in installed template`); } } diff --git a/lib/services/project-templates-service.ts b/lib/services/project-templates-service.ts index 665cf5acea..767a805191 100644 --- a/lib/services/project-templates-service.ts +++ b/lib/services/project-templates-service.ts @@ -62,7 +62,7 @@ export class ProjectTemplatesService implements IProjectTemplatesService { this.$logger.trace(`The template ${templateName} has version ${templateVersionFromPackageJson}.`); if (_.values(constants.TemplateVersions).indexOf(templateVersionFromPackageJson) === -1) { - this.$errors.failWithoutHelp(format(constants.ProjectTemplateErrors.InvalidTemplateVersionStringFormat, templateName, templateVersionFromPackageJson)); + this.$errors.fail(format(constants.ProjectTemplateErrors.InvalidTemplateVersionStringFormat, templateName, templateVersionFromPackageJson)); } return templateVersionFromPackageJson; diff --git a/lib/services/test-execution-service.ts b/lib/services/test-execution-service.ts index 9f9ebb4728..f62daba04f 100644 --- a/lib/services/test-execution-service.ts +++ b/lib/services/test-execution-service.ts @@ -38,29 +38,29 @@ export class TestExecutionService implements ITestExecutionService { // In case you want to debug the unit test runner, add "--inspect-brk=" as a first element in the array of args. const karmaRunner = this.$childProcess.spawn(process.execPath, [path.join(__dirname, "karma-execution.js")], { stdio: ["inherit", "inherit", "inherit", "ipc"] }); const launchKarmaTests = async (karmaData: any) => { - this.$logger.trace("## Unit-testing: Parent process received message", karmaData); - let port: string; - if (karmaData.url) { - port = karmaData.url.port; - const socketIoJsUrl = `http://${karmaData.url.host}/socket.io/socket.io.js`; - const socketIoJs = (await this.$httpClient.httpRequest(socketIoJsUrl)).body; - this.$fs.writeFile(path.join(liveSyncInfo.projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs); - } + this.$logger.trace("## Unit-testing: Parent process received message", karmaData); + let port: string; + if (karmaData.url) { + port = karmaData.url.port; + const socketIoJsUrl = `http://${karmaData.url.host}/socket.io/socket.io.js`; + const socketIoJs = (await this.$httpClient.httpRequest(socketIoJsUrl)).body; + this.$fs.writeFile(path.join(liveSyncInfo.projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs); + } - if (karmaData.launcherConfig) { - const configOptions: IKarmaConfigOptions = JSON.parse(karmaData.launcherConfig); - const configJs = this.generateConfig(port, configOptions); - this.$fs.writeFile(path.join(liveSyncInfo.projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs); - } + if (karmaData.launcherConfig) { + const configOptions: IKarmaConfigOptions = JSON.parse(karmaData.launcherConfig); + const configJs = this.generateConfig(port, configOptions); + this.$fs.writeFile(path.join(liveSyncInfo.projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs); + } - // Prepare the project AFTER the TestExecutionService.CONFIG_FILE_NAME file is created in node_modules - // so it will be sent to device. + // Prepare the project AFTER the TestExecutionService.CONFIG_FILE_NAME file is created in node_modules + // so it will be sent to device. - await this.$runController.run({ - liveSyncInfo, - deviceDescriptors - }); - }; + await this.$runController.run({ + liveSyncInfo, + deviceDescriptors + }); + }; karmaRunner.on("message", (karmaData: any) => { this.$logger.trace(`The received message from karma is: `, karmaData); @@ -80,7 +80,6 @@ export class TestExecutionService implements ITestExecutionService { if (exitCode !== 0) { //End our process with a non-zero exit code const testError = new Error("Test run failed."); - testError.suppressCommandHelp = true; reject(testError); } else { resolve(); diff --git a/lib/services/test-initialization-service.ts b/lib/services/test-initialization-service.ts index 226cd3fc22..c2d7f6220c 100644 --- a/lib/services/test-initialization-service.ts +++ b/lib/services/test-initialization-service.ts @@ -20,7 +20,7 @@ export class TestInitializationService implements ITestInitializationService { .map(dependency => { const dependencyVersion = dependenciesVersions[dependency.name]; if (!dependencyVersion) { - this.$errors.failWithoutHelp(`'${dependency}' is not a registered dependency.`); + this.$errors.fail(`'${dependency}' is not a registered dependency.`); } return { ...dependency, version: dependencyVersion }; }); diff --git a/lib/services/xcproj-service.ts b/lib/services/xcproj-service.ts index 966f20880c..066466ab14 100644 --- a/lib/services/xcproj-service.ts +++ b/lib/services/xcproj-service.ts @@ -23,7 +23,7 @@ class XcprojService implements IXcprojService { if (xcprojInfo.shouldUseXcproj && !xcprojInfo.xcprojAvailable) { const errorMessage = `You are using CocoaPods version ${xcprojInfo.cocoapodVer} which does not support Xcode ${xcprojInfo.xcodeVersion.major}.${xcprojInfo.xcodeVersion.minor} yet.${EOL}${EOL}You can update your cocoapods by running $sudo gem install cocoapods from a terminal.${EOL}${EOL}In order for the NativeScript CLI to be able to work correctly with this setup you need to install xcproj command line tool and add it to your PATH. Xcproj can be installed with homebrew by running $ brew install xcproj from the terminal`; if (opts.shouldFail) { - this.$errors.failWithoutHelp(errorMessage); + this.$errors.fail(errorMessage); } else { this.$logger.warn(errorMessage); } @@ -74,7 +74,7 @@ class XcprojService implements IXcprojService { if (xcprojInfo.shouldUseXcproj && !xcprojInfo.xcprojAvailable) { const errorMessage = `You are using CocoaPods version ${xcprojInfo.cocoapodVer} which does not support Xcode ${xcprojInfo.xcodeVersion.major}.${xcprojInfo.xcodeVersion.minor} yet.${EOL}${EOL}You can update your cocoapods by running $sudo gem install cocoapods from a terminal.${EOL}${EOL}In order for the NativeScript CLI to be able to work correctly with this setup you need to install xcproj command line tool and add it to your PATH. Xcproj can be installed with homebrew by running $ brew install xcproj from the terminal`; - this.$errors.failWithoutHelp(errorMessage); + this.$errors.fail(errorMessage); return true; } diff --git a/lib/yarn-package-manager.ts b/lib/yarn-package-manager.ts index d4c9224e87..77bb616cb1 100644 --- a/lib/yarn-package-manager.ts +++ b/lib/yarn-package-manager.ts @@ -62,7 +62,7 @@ export class YarnPackageManager extends BasePackageManager { try { viewResult = await this.$childProcess.exec(`yarn info ${packageName} ${flags}`); } catch (e) { - this.$errors.failWithoutHelp(e.message); + this.$errors.fail(e.message); } const result = JSON.parse(viewResult); diff --git a/test/android-tools-info.ts b/test/android-tools-info.ts index d8fb69c732..e442bf4f71 100644 --- a/test/android-tools-info.ts +++ b/test/android-tools-info.ts @@ -2,6 +2,7 @@ import { Yok } from "../lib/common/yok"; import { AndroidToolsInfo } from "../lib/android-tools-info"; import { format } from "util"; import { assert } from "chai"; +import { ErrorsStub } from "./stubs"; describe("androidToolsInfo", () => { let loggedWarnings: string[] = []; @@ -16,12 +17,8 @@ describe("androidToolsInfo", () => { const createTestInjector = (): IInjector => { const testInjector = new Yok(); testInjector.register("childProcess", {}); - testInjector.register("errors", { - failWithoutHelp: (message: string, ...args: any[]): any => { - const loggedError = format(message, args); - throw new Error(loggedError); - } - }); + + testInjector.register("errors", ErrorsStub); testInjector.register("fs", {}); testInjector.register("hostInfo", {}); testInjector.register("logger", { diff --git a/test/options.ts b/test/options.ts index 92363d685d..b62083ebf4 100644 --- a/test/options.ts +++ b/test/options.ts @@ -30,7 +30,7 @@ describe("options", () => { testInjector = createTestInjector(); const errors = new Errors(testInjector); - errors.failWithoutHelp = ((message: string, ...args: any[]): void => { + errors.failWithHelp = ((message: string, ...args: any[]): void => { isExecutionStopped = true; }); errors.fail = ((message: string, ...args: any[]): void => { @@ -275,7 +275,8 @@ describe("options", () => { it(`should fail when ${testCase.name}`, () => { let actualError = null; const errors = testInjector.resolve("errors"); - errors.failWithoutHelp = (error: string) => actualError = error; + errors.fail = (error: string) => actualError = error; + errors.failWithHelp = (error: string) => actualError = error; (testCase.args || []).forEach(arg => process.argv.push(arg)); const options: any = createOptions(testInjector); diff --git a/test/platform-commands.ts b/test/platform-commands.ts index 392ffea227..3447a627a9 100644 --- a/test/platform-commands.ts +++ b/test/platform-commands.ts @@ -51,11 +51,16 @@ class ErrorsNoFailStub implements IErrors { printCallStack: boolean = false; fail(formatStr: string, ...args: any[]): never; - fail(opts: { formatStr?: string; errorCode?: number; suppressCommandHelp?: boolean }, ...args: any[]): never; + fail(opts: IFailOptions, ...args: any[]): never; fail(...args: any[]): never { throw new Error(); } - failWithoutHelp(message: string, ...args: any[]): never { - throw new Error(); + + failWithoutHelp(opts: string | IFailOptions, ...args: any[]): never { + return this.fail(opts, args); + } + + failWithHelp(opts: string | IFailOptions, ...args: any[]): never { + return this.fail(opts, args); } async beginCommand(action: () => Promise, printHelpCommand: () => Promise): Promise { diff --git a/test/services/livesync/android-livesync-tool.ts b/test/services/livesync/android-livesync-tool.ts index 49f14905bc..25224f7a7e 100644 --- a/test/services/livesync/android-livesync-tool.ts +++ b/test/services/livesync/android-livesync-tool.ts @@ -16,7 +16,7 @@ const protocolVersion = "0.2.0"; class TestSocket extends LiveSyncSocket { public accomulatedData: Buffer[] = []; - public connect () { + public connect() { return this; } @@ -75,6 +75,9 @@ const createTestInjector = (socket: INetSocket, fileStreams: IDictionary socket); testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); testInjector.register("errors", { + failWithHelp: (message: string): void => { + throw new Error(message); + }, fail: (message: string) => { throw new Error(message); }, @@ -102,18 +105,18 @@ const getFileContentSize = (buffer: Buffer, offset: number) => { const fileContentSizeEnd = fileContentSizeBegin + fileContentSizeLength; const fileContentSize = Number(buffer.toString("utf8", fileContentSizeBegin, fileContentSizeEnd)); - return {fileContentSize, fileContentSizeEnd}; + return { fileContentSize, fileContentSizeEnd }; }; const getFileContent = (buffer: Buffer, offset: number, contentLength: number) => { const fileContentEnd = offset + Number(contentLength); const fileContent = buffer.toString("utf8", offset, fileContentEnd); - return {fileContent, fileContentEnd}; + return { fileContent, fileContentEnd }; }; const getOperation = (buffer: Buffer) => { - const operation = buffer.toString("utf8", 0 , 1); + const operation = buffer.toString("utf8", 0, 1); return Number(operation); }; @@ -136,10 +139,10 @@ const getSendFileData = (buffers: Buffer[]) => { const { fileContentSize, fileContentSizeEnd } = getFileContentSize(buffer, fileNameEnd); const headerHashMatch = compareHash(buffer, 0, fileContentSizeEnd, fileContentSizeEnd); const headerHashEnd = fileContentSizeEnd + 16; - const {fileContent, fileContentEnd} = getFileContent(buffer, headerHashEnd, fileContentSize); + const { fileContent, fileContentEnd } = getFileContent(buffer, headerHashEnd, fileContentSize); const fileHashMatch = compareHash(buffer, headerHashEnd, fileContentEnd, fileContentEnd); - return {operation, fileName, fileContent, headerHashMatch, fileHashMatch}; + return { operation, fileName, fileContent, headerHashMatch, fileHashMatch }; }; const getRemoveFileData = (buffers: Buffer[]) => { @@ -148,7 +151,7 @@ const getRemoveFileData = (buffers: Buffer[]) => { const { fileName, fileNameEnd } = getFileName(buffer); const headerHashMatch = compareHash(buffer, 0, fileNameEnd, fileNameEnd); - return { operation, fileName, headerHashMatch}; + return { operation, fileName, headerHashMatch }; }; const getSyncData = (buffers: Buffer[]) => { @@ -157,7 +160,7 @@ const getSyncData = (buffers: Buffer[]) => { const operationUid = buffer.toString("utf8", 1, 33); const doRefresh = buffer.readUInt8(33); - return {operationUid, doRefresh, operation}; + return { operationUid, doRefresh, operation }; }; const getSyncResponse = (reportCode: number, message: string) => { @@ -180,11 +183,11 @@ const getHandshakeBuffer = () => { return handshakeBuffer; }; -const stubSocketEventAttach = (socket: any, sandbox: sinon.SinonSandbox, attachMethod: string, eventName: string, data: any, attachCountForAction: number, emitEvent?: string ) => { +const stubSocketEventAttach = (socket: any, sandbox: sinon.SinonSandbox, attachMethod: string, eventName: string, data: any, attachCountForAction: number, emitEvent?: string) => { const originalMethod = socket[attachMethod]; let attachCount = 0; emitEvent = emitEvent || eventName; - sandbox.stub(socket, attachMethod).callsFake(function(event: string) { + sandbox.stub(socket, attachMethod).callsFake(function (event: string) { originalMethod.apply(this, arguments); if (eventName === event) { attachCount++; diff --git a/test/services/playground/preview-schema-service.ts b/test/services/playground/preview-schema-service.ts index abcb4c191d..5d29550ebf 100644 --- a/test/services/playground/preview-schema-service.ts +++ b/test/services/playground/preview-schema-service.ts @@ -75,7 +75,7 @@ describe("PreviewSchemaService", () => { let actualError = null; if (testCase.expectedToThrow) { const errors = injector.resolve("errors"); - errors.failWithoutHelp = (err: string) => actualError = err; + errors.fail = (err: string) => actualError = err; } const schemaData = previewSchemaService.getSchemaData("someTestProjectDir"); diff --git a/test/stubs.ts b/test/stubs.ts index f478556883..52106d0fe2 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -85,7 +85,7 @@ export class FileSystemStub implements IFileSystem { return undefined; } - readFile(filename: string): NodeBuffer | string { + readFile(filename: string): Buffer | string { return undefined; } @@ -192,14 +192,18 @@ export class FileSystemStub implements IFileSystem { export class ErrorsStub implements IErrors { fail(formatStr: string, ...args: any[]): never; - fail(opts: { formatStr?: string; errorCode?: number; suppressCommandHelp?: boolean }, ...args: any[]): never; + fail(opts: IFailOptions, ...args: any[]): never; fail(...args: any[]): never { throw new Error(require("util").format.apply(null, args || [])); } - failWithoutHelp(message: string, ...args: any[]): never { - throw new Error(message); + failWithoutHelp(opts: string | IFailOptions, ...args: any[]): never { + return this.fail(opts, args); + } + + failWithHelp(opts: string | IFailOptions, ...args: any[]): never { + return this.fail(opts, args); } async beginCommand(action: () => Promise, printHelpCommand: () => Promise): Promise { diff --git a/test/test-bootstrap.ts b/test/test-bootstrap.ts index 5468c17745..ccc824db86 100644 --- a/test/test-bootstrap.ts +++ b/test/test-bootstrap.ts @@ -22,7 +22,8 @@ $injector.register("analyticsService", { } }); -import { PerformanceService } from "./stubs"; +import { PerformanceService, LoggerStub } from "./stubs"; +$injector.register("logger", LoggerStub); $injector.register("performanceService", PerformanceService); // Converts the js callstack to typescript diff --git a/tslint.json b/tslint.json index 3c69354342..1e26977ae7 100644 --- a/tslint.json +++ b/tslint.json @@ -1,6 +1,7 @@ { "rulesDirectory": "node_modules/tslint-microsoft-contrib", "rules": { + "deprecation": true, "class-name": true, "curly": true, "eofline": true,