diff --git a/docs/man_pages/lib-management/plugin-add.md b/docs/man_pages/lib-management/plugin-add.md index 6671048aae..15e2d715d6 100644 --- a/docs/man_pages/lib-management/plugin-add.md +++ b/docs/man_pages/lib-management/plugin-add.md @@ -1,11 +1,11 @@ -plugin add +plugin add ========== Usage | Synopsis ------|------- General | `$ tns plugin add ` -<% if(isConsole) { %>Installs the specified plugin and any packages that it depends on.<% } %> +<% if(isConsole) { %>Installs the specified plugin and any packages that it depends on.<% } %> <% if(isHtml) { %>Installs the specified plugin and its dependencies in the local `node_modules` folder, adds it to the `dependencies` section in `package.json`, and prepares the plugin for all installed platforms. If you have not configured any platforms for the project, the NativeScript CLI will prepare the plugin when you add a platform. For more information about working with plugins, see [NativeScript Plugins](https://github.com/NativeScript/nativescript-cli/blob/master/PLUGINS.md).<% } %> ### Attributes @@ -28,4 +28,6 @@ Command | Description ----------|---------- [plugin](plugin.html) | Lets you manage the plugins for your project. [plugin remove](plugin-remove.html) | Uninstalls the specified plugin and its dependencies. -<% } %> \ No newline at end of file +[plugin find](plugin-find.html) | Finds NativeScript plugins in npm. +[plugin search](plugin-search.html) | Finds NativeScript plugins in npm. +<% } %> diff --git a/docs/man_pages/lib-management/plugin-find.md b/docs/man_pages/lib-management/plugin-find.md new file mode 100644 index 0000000000..62ca36627d --- /dev/null +++ b/docs/man_pages/lib-management/plugin-find.md @@ -0,0 +1,29 @@ +plugin find +========== + +Usage | Synopsis +---|--- +General | `$ tns plugin find [] [--all] [--count ]` + +Finds NativeScript plugins in npm. + +### Options +* `--all` - Specifies that all results will be shown at once. +* `--count` - Specifies the number of results to show at a time. If not set, the default value is 10. After showing the specified number of results, the CLI will prompt you to continue showing more results or to exit the operation. + +> **NOTE:** You cannot set --all and --count simultaneously. + +### Attributes +* `` is the name of plugin that you want to find. When specified the search string in npm will be "`nativescript `". +* `` is the number of the plugins to display. + +<% if(isHtml) { %> +### Related Commands + +Command | Description +----------|---------- +[plugin](plugin.html) | Lets you manage the plugins for your project. +[plugin add](plugin-add.html) | Installs the specified plugin and its dependencies. +[plugin remove](plugin-remove.html) | Uninstalls the specified plugin and its dependencies. +[plugin search](plugin-search.html) | Finds NativeScript plugins in npm. +<% } %> diff --git a/docs/man_pages/lib-management/plugin-remove.md b/docs/man_pages/lib-management/plugin-remove.md index 214127ff91..b850ed5c38 100644 --- a/docs/man_pages/lib-management/plugin-remove.md +++ b/docs/man_pages/lib-management/plugin-remove.md @@ -1,4 +1,4 @@ -plugin remove +plugin remove ========== Usage | Synopsis @@ -12,11 +12,13 @@ General | `$ tns plugin remove ` * `` is the name of the plugin as listed in its `package.json` file. -<% if(isHtml) { %> +<% if(isHtml) { %> ### Related Commands Command | Description ----------|---------- [plugin](plugin.html) | Lets you manage the plugins for your project. [plugin add](plugin-add.html) | Installs the specified plugin and its dependencies. -<% } %> \ No newline at end of file +[plugin find](plugin-find.html) | Finds NativeScript plugins in npm. +[plugin search](plugin-search.html) | Finds NativeScript plugins in npm. +<% } %> diff --git a/docs/man_pages/lib-management/plugin-search.md b/docs/man_pages/lib-management/plugin-search.md new file mode 100644 index 0000000000..ad0b9d534d --- /dev/null +++ b/docs/man_pages/lib-management/plugin-search.md @@ -0,0 +1,29 @@ +plugin search +========== + +Usage | Synopsis +---|--- +General | `$ tns plugin search [] [--all] [--count ]` + +Finds NativeScript plugins in npm. + +### Options +* `--all` - Specifies that all results will be shown at once. +* `--count` - Specifies the number of results to show at a time. If not set, the default value is 10. After showing the specified number of results, the CLI will prompt you to continue showing more results or to exit the operation. + +> **NOTE:** You cannot set --all and --count simultaneously. + +### Attributes +* `` is the name of plugin that you want to find. When specified the search string in npm will be "`nativescript `". +* `` is the number of the plugins to display. + +<% if(isHtml) { %> +### Related Commands + +Command | Description +----------|---------- +[plugin](plugin.html) | Lets you manage the plugins for your project. +[plugin add](plugin-add.html) | Installs the specified plugin and its dependencies. +[plugin remove](plugin-remove.html) | Uninstalls the specified plugin and its dependencies. +[plugin find](plugin-find.html) | Finds NativeScript plugins in npm. +<% } %> diff --git a/docs/man_pages/lib-management/plugin.md b/docs/man_pages/lib-management/plugin.md index 630f1bfdd6..c22f74beef 100644 --- a/docs/man_pages/lib-management/plugin.md +++ b/docs/man_pages/lib-management/plugin.md @@ -1,4 +1,4 @@ -plugin +plugin ========== Usage | Synopsis @@ -12,12 +12,16 @@ Lets you manage the plugins for your project. `` extends the `plugin` command. You can set the following values for this attribute. * `add` - Installs the specified plugin and its dependencies. * `remove` - Uninstalls the specified plugin and its dependencies. +* `find` - Finds NativeScript plugins in npm. +* `search` - Finds NativeScript plugins in npm. -<% if(isHtml) { %> +<% if(isHtml) { %> ### Related Commands Command | Description ----------|---------- [plugin add](plugin-add.html) | Installs the specified plugin and its dependencies. [plugin remove](plugin-remove.html) | Uninstalls the specified plugin and its dependencies. -<% } %> \ No newline at end of file +[plugin find](plugin-find.html) | Finds NativeScript plugins in npm. +[plugin search](plugin-search.html) | Finds NativeScript plugins in npm. +<% } %> diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index 614b1957e9..8ae93c5714 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -77,6 +77,8 @@ $injector.require("broccoliPluginWrapper", "./tools/broccoli/broccoli-plugin-wra $injector.require("pluginVariablesService", "./services/plugin-variables-service"); $injector.require("pluginsService", "./services/plugins-service"); $injector.requireCommand("plugin|*list", "./commands/plugin/list-plugins"); +$injector.requireCommand("plugin|find", "./commands/plugin/find-plugins"); +$injector.requireCommand("plugin|search", "./commands/plugin/find-plugins"); $injector.requireCommand("plugin|add", "./commands/plugin/add-plugin"); $injector.requireCommand("plugin|remove", "./commands/plugin/remove-plugin"); diff --git a/lib/commands/plugin/find-plugins.ts b/lib/commands/plugin/find-plugins.ts new file mode 100644 index 0000000000..59053e9731 --- /dev/null +++ b/lib/commands/plugin/find-plugins.ts @@ -0,0 +1,100 @@ +/// +"use strict"; +import { createTable, isInteractive } from "../../common/helpers"; +import { NATIVESCRIPT_KEY_NAME } from "../../constants"; +import Future = require("fibers/future"); + +export class FindPluginsCommand implements ICommand { + private static COUNT_OF_PLUGINS_TO_DISPLAY: number = 10; + + constructor(private $pluginsService: IPluginsService, + private $errors: IErrors, + private $logger: ILogger, + private $prompter: IPrompter, + private $options: IOptions, + private $progressIndicator: IProgressIndicator) { } + + execute(args: string[]): IFuture { + return (() => { + let filter: string[] = this.prepareFilter(args); + + let pluginsFuture: IFuture> = this.$pluginsService.getAvailable(filter); + if (this.$options.json) { + this.$logger.out(JSON.stringify(pluginsFuture.wait())); + return; + } + + this.$logger.printInfoMessageOnSameLine("Searching npm please be patient..."); + this.$progressIndicator.showProgressIndicator(pluginsFuture, 500).wait(); + let plugins: IDictionary = pluginsFuture.get(); + + this.$logger.out("Available NativeScript plugins"); + this.showPlugins(plugins).wait(); + }).future()(); + } + + canExecute(args: string[]): IFuture { + return Future.fromResult(true); + } + + public allowedParameters: ICommandParameter[] = []; + + private showPlugins(plugins: IDictionary): IFuture { + return (() => { + let allPluginsNames: string[] = _.keys(plugins).sort(); + + let count: number = this.$options.count || FindPluginsCommand.COUNT_OF_PLUGINS_TO_DISPLAY; + + if (!isInteractive() || this.$options.all) { + count = allPluginsNames.length; + } + + let data: string[][] = []; + + let pluginsToDisplay: string[] = allPluginsNames.splice(0, count); + let shouldDisplayMorePlugins: boolean = true; + + do { + data = this.createTableCells(plugins, pluginsToDisplay); + + let table: any = this.createPluginsTable(data); + + this.$logger.out(table.toString()); + + pluginsToDisplay = allPluginsNames.splice(0, count); + + if (!pluginsToDisplay || pluginsToDisplay.length < 1) { + return; + } + + shouldDisplayMorePlugins = this.$prompter.confirm("Load more plugins?").wait(); + } while (shouldDisplayMorePlugins); + }).future()(); + } + + private createPluginsTable(data: string[][]): any { + let headers: string[] = ["Plugin", "Version", "Description"]; + + let table: any = createTable(headers, data); + + return table; + } + + private createTableCells(plugins: IDictionary, pluginsToDisplay: string[]): string[][] { + return pluginsToDisplay.map(pluginName => { + let pluginDetails: any = plugins[pluginName]; + return [pluginName, pluginDetails.version, pluginDetails.description || ""]; + }); + } + + private prepareFilter(args: string[]): string[] { + return _(args || []) + .map(arg => arg.toLowerCase()) + .concat(NATIVESCRIPT_KEY_NAME) + .uniq() + .value(); + } + +} + +$injector.registerCommand(["plugin|find", "plugin|search"], FindPluginsCommand); diff --git a/lib/commands/plugin/list-plugins.ts b/lib/commands/plugin/list-plugins.ts index 63b1236573..995b9fd75a 100644 --- a/lib/commands/plugin/list-plugins.ts +++ b/lib/commands/plugin/list-plugins.ts @@ -1,38 +1,30 @@ /// "use strict"; - import { createTable } from "../../common/helpers"; export class ListPluginsCommand implements ICommand { constructor(private $pluginsService: IPluginsService, - private $logger: ILogger, - private $options: IOptions) { } + private $logger: ILogger) { } allowedParameters: ICommandParameter[] = []; public execute(args: string[]): IFuture { return (() => { let installedPlugins: IPackageJsonDepedenciesResult = this.$pluginsService.getDependenciesFromPackageJson().wait(); - let headers: string[] = ["Plugin", "Version"]; - let dependenciesData: string[][] = []; - let devDependenciesData: string[][] = []; - _.each(installedPlugins.dependencies, (dependency: IBasePluginData) => { - dependenciesData.push([dependency.name, dependency.version]); - }); + let headers: string[] = ["Plugin", "Version"]; + let dependenciesData: string[][] = this.createTableCells(installedPlugins.dependencies); let dependenciesTable: any = createTable(headers, dependenciesData); - this.$logger.out("Dependencies"); + this.$logger.out("Dependencies:"); this.$logger.out(dependenciesTable.toString()); if (installedPlugins.devDependencies && installedPlugins.devDependencies.length) { - _.each(installedPlugins.devDependencies, (dependency: IBasePluginData) => { - devDependenciesData.push([dependency.name, dependency.version]); - }); + let devDependenciesData: string[][] = this.createTableCells(installedPlugins.devDependencies); let devDependenciesTable: any = createTable(headers, devDependenciesData); - this.$logger.out("Dev Dependencies"); + this.$logger.out("Dev Dependencies:"); this.$logger.out(devDependenciesTable.toString()); } else { this.$logger.out("There are no dev dependencies."); @@ -42,10 +34,14 @@ export class ListPluginsCommand implements ICommand { let viewDevDependenciesCommand: string = "npm view grep devDependencies".cyan.toString(); this.$logger.warn("NOTE:"); - this.$logger.warn(`If you want to see the dependencies of installed plugin use ${viewDependenciesCommand}`); - this.$logger.warn(`If you want to see the dev dependencies of installed plugin use ${viewDevDependenciesCommand}`); + this.$logger.warn(`If you want to check the dependencies of installed plugin use ${viewDependenciesCommand}`); + this.$logger.warn(`If you want to check the dev dependencies of installed plugin use ${viewDevDependenciesCommand}`); }).future()(); } + + private createTableCells(items: IBasePluginData[]): string[][] { + return items.map(item => [item.name, item.version]); + } } $injector.registerCommand("plugin|*list", ListPluginsCommand); diff --git a/lib/common b/lib/common index be182d01b9..0361153a06 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit be182d01b91e9a448948b90379b7829d9484f16a +Subproject commit 0361153a06ed4a2f866b415f5b0adca1b492a244 diff --git a/lib/declarations.ts b/lib/declarations.ts index 89e9dd7daf..f659e99aca 100644 --- a/lib/declarations.ts +++ b/lib/declarations.ts @@ -7,6 +7,7 @@ interface INodePackageManager { cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture; view(packageName: string, propertyName: string): IFuture; executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture; + search(filter: string[], silent: boolean): IFuture; } interface INpmInstallationManager { @@ -58,6 +59,7 @@ interface ILiveSyncService { } interface IOptions extends ICommonOptions { + all: boolean; baseConfig: string; client: boolean; compileSdk: number; @@ -267,5 +269,5 @@ interface IProjectNameService { * @param {IOptions} current command options. * @return {IFuture} returns the selected name of the project. */ - ensureValidName(projectName: string, validateOptions?: {force: boolean}): IFuture; + ensureValidName(projectName: string, validateOptions?: { force: boolean }): IFuture; } diff --git a/lib/definitions/plugins.d.ts b/lib/definitions/plugins.d.ts index ff1241c0ac..416fea5998 100644 --- a/lib/definitions/plugins.d.ts +++ b/lib/definitions/plugins.d.ts @@ -1,6 +1,7 @@ interface IPluginsService { add(plugin: string): IFuture; // adds plugin by name, github url, local path and et. remove(pluginName: string): IFuture; // removes plugin only by name + getAvailable(filter: string[]): IFuture>; // gets all available plugins prepare(pluginData: IDependencyData, platform: string): IFuture; getAllInstalledPlugins(): IFuture; ensureAllDependenciesAreInstalled(): IFuture; diff --git a/lib/node-package-manager.ts b/lib/node-package-manager.ts index 47cce4927b..428a216e5b 100644 --- a/lib/node-package-manager.ts +++ b/lib/node-package-manager.ts @@ -29,7 +29,7 @@ export class NodePackageManager implements INodePackageManager { } else { let future = new Future(); npm.load(config, (err: Error) => { - if(err) { + if (err) { future.throw(err); } else { future.return(); @@ -40,7 +40,7 @@ export class NodePackageManager implements INodePackageManager { } public install(packageName: string, pathToSave: string, config?: any): IFuture { - if(this.$options.ignoreScripts) { + if (this.$options.ignoreScripts) { config = config || {}; config["ignore-scripts"] = true; } @@ -49,7 +49,12 @@ export class NodePackageManager implements INodePackageManager { } public uninstall(packageName: string, config?: any, path?: string): IFuture { - return this.loadAndExecute("uninstall", [[packageName]], { config, path}); + return this.loadAndExecute("uninstall", [[packageName]], { config, path }); + } + + public search(filter: string[], silent: boolean): IFuture { + let args = (([filter] || [])).concat(silent); + return this.loadAndExecute("search", args); } public cache(packageName: string, version: string, config?: any): IFuture { @@ -86,7 +91,7 @@ export class NodePackageManager implements INodePackageManager { npm.prefix = oldNpmPath; } - if(err) { + if (err) { future.throw(err); } else { future.return(data); diff --git a/lib/options.ts b/lib/options.ts index af693f5952..ccc060c0bf 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -37,7 +37,7 @@ export class Options extends commonOptionsLibPath.OptionsBase { baseConfig: { type: OptionType.String }, platformTemplate: { type: OptionType.String }, ng: {type: OptionType.Boolean }, - available: {type: OptionType.Boolean } + all: {type: OptionType.Boolean } }, path.join($hostInfo.isWindows ? process.env.AppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"), $errors, $staticConfig); diff --git a/lib/services/plugins-service.ts b/lib/services/plugins-service.ts index ee0c8d7a2a..f18b249e07 100644 --- a/lib/services/plugins-service.ts +++ b/lib/services/plugins-service.ts @@ -11,19 +11,31 @@ export class PluginsService implements IPluginsService { private static NPM_CONFIG = { save: true }; + private get $projectData(): IProjectData { + return this.$injector.resolve("projectData"); + } + private get $platformsData(): IPlatformsData { + return this.$injector.resolve("platformsData"); + } + private get $pluginVariablesService(): IPluginVariablesService { + return this.$injector.resolve("pluginVariablesService"); + } + private get $projectDataService(): IProjectDataService { + return this.$injector.resolve("projectDataService"); + } + private get $projectFilesManager(): IProjectFilesManager { + return this.$injector.resolve("projectFilesManager"); + } + private get $broccoliBuilder(): IBroccoliBuilder { + return this.$injector.resolve("broccoliBuilder"); + } - constructor(private $broccoliBuilder: IBroccoliBuilder, - private $platformsData: IPlatformsData, - private $npm: INodePackageManager, + constructor(private $npm: INodePackageManager, private $fs: IFileSystem, - private $projectData: IProjectData, - private $projectDataService: IProjectDataService, private $childProcess: IChildProcess, private $options: IOptions, private $logger: ILogger, private $errors: IErrors, - private $pluginVariablesService: IPluginVariablesService, - private $projectFilesManager: IProjectFilesManager, private $injector: IInjector) { } public add(plugin: string): IFuture { @@ -93,6 +105,11 @@ export class PluginsService implements IPluginsService { }).future()(); } + public getAvailable(filter: string[]): IFuture> { + let silent: boolean = true; + return this.$npm.search(filter, silent); + } + public prepare(dependencyData: IDependencyData, platform: string): IFuture { return (() => { platform = platform.toLowerCase(); @@ -150,9 +167,9 @@ export class PluginsService implements IPluginsService { public getDependenciesFromPackageJson(): IFuture { return (() => { let packageJson = this.$fs.readJson(this.getPackageJsonFilePath()).wait(); - let dependencies: IBasePluginData[] = this.mapDependenciesToBaseIPluginData(packageJson.dependencies); + let dependencies: IBasePluginData[] = this.getBasicPluginInformation(packageJson.dependencies); - let devDependencies: IBasePluginData[] = this.mapDependenciesToBaseIPluginData(packageJson.devDependencies); + let devDependencies: IBasePluginData[] = this.getBasicPluginInformation(packageJson.devDependencies); return { dependencies, @@ -161,17 +178,11 @@ export class PluginsService implements IPluginsService { }).future()(); } - private mapDependenciesToBaseIPluginData(dependencies: any): IBasePluginData[] { - let result: IBasePluginData[] = []; - - _.forEach(_.keys(dependencies), (key: string) => { - result.push({ - name: key, - version: dependencies[key] - }); - }); - - return result; + private getBasicPluginInformation(dependencies: any): IBasePluginData[] { + return _.map(dependencies, (version: string, key: string) => ({ + name: key, + version: version + })); } private get nodeModulesPath(): string { diff --git a/package.json b/package.json index eeb2e6caaf..4d4cb68030 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "bufferutil": "https://github.com/telerik/bufferutil/tarball/v1.0.1.1", "byline": "4.2.1", "chalk": "1.1.0", - "cli-table": "https://github.com/telerik/cli-table/tarball/v0.3.1.1", + "cli-table": "https://github.com/telerik/cli-table/tarball/v0.3.1.2", "clui": "0.3.1", "colors": "1.1.2", "esprima": "2.7.0",