|
1 | 1 | import * as path from "path"; |
2 | 2 | import { cache, exported } from "../common/decorators"; |
3 | 3 | import * as constants from "../constants"; |
| 4 | +import { createRegExp, regExpEscape } from "../common/helpers"; |
4 | 5 |
|
5 | 6 | export class ExtensibilityService implements IExtensibilityService { |
6 | 7 | private get pathToExtensions(): string { |
@@ -107,6 +108,63 @@ export class ExtensibilityService implements IExtensibilityService { |
107 | 108 | } |
108 | 109 | } |
109 | 110 |
|
| 111 | + public async getExtensionNameWhereCommandIsRegistered(inputOpts: IGetExtensionCommandInfoParams): Promise<IExtensionCommandInfo> { |
| 112 | + let allExtensions: INpmsSingleResultData[] = []; |
| 113 | + |
| 114 | + try { |
| 115 | + const npmsResult = await this.$npm.searchNpms("nativescript:extension"); |
| 116 | + allExtensions = npmsResult.results || []; |
| 117 | + } catch (err) { |
| 118 | + this.$logger.trace(`Unable to find extensions via npms. Error is: ${err}`); |
| 119 | + return null; |
| 120 | + } |
| 121 | + |
| 122 | + const defaultCommandRegExp = new RegExp(`${regExpEscape(inputOpts.defaultCommandDelimiter)}.*`); |
| 123 | + const commandDelimiterRegExp = createRegExp(inputOpts.commandDelimiter, "g"); |
| 124 | + |
| 125 | + for (const extensionData of allExtensions) { |
| 126 | + const extensionName = extensionData.package.name; |
| 127 | + |
| 128 | + try { |
| 129 | + // now get full package.json for the latest version of the package |
| 130 | + const registryData = await this.$npm.getRegistryPackageData(extensionName); |
| 131 | + const latestPackageData = registryData.versions[registryData["dist-tags"].latest]; |
| 132 | + const commands: string[] = latestPackageData && latestPackageData.nativescript && latestPackageData.nativescript.commands; |
| 133 | + if (commands && commands.length) { |
| 134 | + // For each default command we need to add its short syntax in the array of commands. |
| 135 | + // For example in case there's a default command called devices list, the commands array will contain devices|*list. |
| 136 | + // However, in case the user executes just tns devices, CLI will still execute the tns devices list command. |
| 137 | + // So we need to add the devices command as well. |
| 138 | + _.filter(commands, command => command.indexOf(inputOpts.defaultCommandDelimiter) !== -1) |
| 139 | + .forEach(defaultCommand => { |
| 140 | + commands.push(defaultCommand.replace(defaultCommandRegExp, "")); |
| 141 | + }); |
| 142 | + |
| 143 | + const copyOfFullArgs = _.clone(inputOpts.inputStrings); |
| 144 | + while (copyOfFullArgs.length) { |
| 145 | + const currentCommand = copyOfFullArgs.join(inputOpts.commandDelimiter).toLowerCase(); |
| 146 | + |
| 147 | + if (_.some(commands, c => c.toLowerCase() === currentCommand)) { |
| 148 | + const beautifiedCommandName = currentCommand.replace(commandDelimiterRegExp, " "); |
| 149 | + return { |
| 150 | + extensionName, |
| 151 | + registeredCommandName: currentCommand, |
| 152 | + installationMessage: `The command ${beautifiedCommandName} is registered in extension ${extensionName}. You can install it by executing 'tns extension install ${extensionName}'` |
| 153 | + }; |
| 154 | + } |
| 155 | + |
| 156 | + copyOfFullArgs.splice(-1, 1); |
| 157 | + } |
| 158 | + } |
| 159 | + } catch (err) { |
| 160 | + // We do not want to stop the whole process in case we are unable to find data for one of the extensions. |
| 161 | + this.$logger.trace(`Unable to get data for ${extensionName}. Error is: ${err}`); |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + return null; |
| 166 | + } |
| 167 | + |
110 | 168 | private getPathToExtension(extensionName: string): string { |
111 | 169 | return path.join(this.pathToExtensions, constants.NODE_MODULES_FOLDER_NAME, extensionName); |
112 | 170 | } |
|
0 commit comments