diff --git a/.gitignore b/.gitignore index 7bc5cb1..d36d750 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ /lib /node_modules /tmp +.oclif.manifest.json +yarn.lock diff --git a/.images/vscodeScreenshot.png b/.images/vscodeScreenshot.png new file mode 100644 index 0000000..4b7206a Binary files /dev/null and b/.images/vscodeScreenshot.png differ diff --git a/README.md b/README.md index fac3e0c..c6a5e08 100644 --- a/README.md +++ b/README.md @@ -1,261 +1,242 @@ - - - - -oclif: Node.JS Open CLI Framework -================================= - -[![Join the chat at https://gitter.im/oclif/oclif](https://badges.gitter.im/oclif/oclif.svg)](https://gitter.im/oclif/oclif?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Version](https://img.shields.io/npm/v/oclif.svg)](https://npmjs.org/package/oclif) -[![CircleCI](https://circleci.com/gh/oclif/oclif/tree/master.svg?style=shield)](https://circleci.com/gh/oclif/oclif/tree/master) -[![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/oclif/oclif?branch=master&svg=true)](https://ci.appveyor.com/project/heroku/oclif/branch/master) -[![Greenkeeper](https://badges.greenkeeper.io/oclif/oclif.svg)](https://greenkeeper.io/) -[![Known Vulnerabilities](https://snyk.io/test/github/oclif/oclif/badge.svg)](https://snyk.io/test/github/oclif/oclif) -[![Downloads/week](https://img.shields.io/npm/dw/oclif.svg)](https://npmjs.org/package/oclif) -[![License](https://img.shields.io/npm/l/oclif.svg)](https://github.com/oclif/oclif/blob/master/package.json) - +Salesforce Plugin Generator (Beta) +================== -* [๐Ÿ—’ Description](#-description) -* [๐Ÿš€ Getting Started Tutorial](#-getting-started-tutorial) -* [โœจ Features](#-features) -* [๐Ÿ“Œ Requirements](#-requirements) -* [๐ŸŒˆ CLI Types](#-cli-types) -* [๐Ÿ— Usage](#-usage) -* [๐Ÿ“š Examples](#-examples) -* [๐Ÿ”จ Commands](#-commands) -* [๐Ÿญ Related Repositories](#-related-repositories) -* [๐Ÿฆ” Learn More](#-learn-more) -* [๐Ÿ“ฃ Feedback](#-feedback) +* [Description](#description) +* [Usage](#usage) +* [Salesforce CLI Plugin Development ](#salesforce-cli-plugin-development) +* [Plugin Generator Development](#plugin-generator-development) +* [Related Docs and Repositories](#related-docs-and-repositories) -# ๐Ÿ—’ Description - -This is a framework for building CLIs in Node.js. This framework was built out of the [Heroku CLI](https://cli.heroku.com) but generalized to build any custom CLI. It's designed both for simple CLIs that can be just a single file with a few flag options, or for very complex CLIs that have subcommands (like git or heroku). +# Description -[See the docs for more information](http://oclif.io/docs/introduction.html). - -# ๐Ÿš€ Getting Started Tutorial - -The [Getting Started tutorial](http://oclif.io/docs/introduction.html) is a step-by-step guide to introduce you to oclif. If you have not developed anything in a command line before, this tutorial is a great place to get started. - -# โœจ Features - -* **Flag/Argument parsing** - No CLI framework would be complete without a flag parser. We've built a custom one from years of experimentation that we feel consistently handles user input flexible enough for the user to be able to easily use the CLI in ways they expect, but without comprisiming strictness guarantees to the developer. -* **Super Speed** - The overhead for running an oclif CLI command is almost nothing. [It requires very few dependencies](https://www.npmjs.com/package/@oclif/command?activeTab=dependencies). Also, only the command to be executed will be required with node. So large CLIs with many commands will load just as fast as a small one with a single command. -* **CLI Generator** - Run a single command to scaffold out a fully functional CLI and get started quickly. See [Usage](#-usage) below. -* **Testing Helpers** - We've put a lot of work into making commands easily testable and easy to mock out stdout/stderr. The generator will automatically create [scaffolded tests](https://github.com/oclif/example-multi-ts/blob/master/test/commands/hello.test.ts). -* **Auto-documentation** - By default you can pass `--help` to the CLI to get help such as flag options and argument information. This information is also automatically placed in the README whenever the npm package of the CLI is published. See the [multi-command CLI example](https://github.com/oclif/example-multi-ts) -* **Plugins** - Using [plugins](https://oclif.io/docs/plugins.html), users of the CLI can extend it with new functionality, a CLI can be split into modular components, and functionality can be shared amongst multiple CLIs. See [Building your own plugin](https://oclif.io/docs/plugins.html#building-your-own-plugin). -* **Hooks** - Use lifecycle hooks to run functionality any time a CLI starts, or on custom triggers. Use this whenever custom functionality needs to be shared between various components of the CLI. -* **TypeScript (or not)** - Everything in the core of oclif is written in TypeScript and the generator can build fully configured TypeScript CLIs or just plain JavaScript CLIs. By virtue of static properties in TypeScript the syntax is a bit cleaner in TypeScriptโ€”but everything will work no matter which language you choose. If you use plugins support, the CLI will automatically use `ts-node` to run the plugins making it easy and fast to use TypeScript with minimal-to-no boilerplate needed for any oclif CLI. -* **Everything is Customizable** - Pretty much anything can be swapped out and replaced inside oclif if neededโ€”including the arg/flag parser. -* **Coming soon: man pages** - In addition to in-CLI help through `--help` and the README markdown help generation, the CLI can also automatically create man pages for all of its commands. -* **Coming soon: Autocomplete** - Automatically include autocomplete for your CLI. This includes not just command names and flag names, but flag values as well. For example, it's easy to configure the Heroku CLI to have completions for Heroku app names: - -``` -$ heroku info --app= # will complete with all the Heroku apps a user has in their account -``` - -# ๐Ÿ“Œ Requirements - -Only Node 8+ is supported. Node 6 will reach end-of-life April 2019. At that point we will continue to support the current LTS version of node. You can add the [node](https://www.npmjs.com/package/node) package to your CLI to ensure users are on Node 8. - -# ๐ŸŒˆ CLI Types - -With oclif you can create 2 different CLI types, single and multi. - -Single CLIs are like `ls` or `cat`. They can accept arguments and flags. Single CLIs can [optionally be just be a single file](https://github.com/oclif/command). - -Multi CLIs are like `git` or `heroku`. They have subcommands that are themselves single CLIs. In the `package.json` there is a field `oclif.commands` that points to a directory. This directory contains all the subcommands for the CLI. For example, if you had a CLI called `mycli` with the commands `mycli create` and `mycli destroy`, you would have a project like the following: +This is the generator plugin for building plugins for the Salesforce CLI. The generated sfdx plugin and command are built on top of the [oclif cli framework](https://github.com/oclif/oclif). +____ +**As a beta feature, Salesforce Plugin Generator is a preview and isnโ€™t part of the โ€œServicesโ€ under your master subscription agreement with Salesforce. Use this feature at your sole discretion, and make your purchase decisions only on the basis of generally available products and features. Salesforce doesnโ€™t guarantee general availability of this feature within any particular time frame or at all, and we can discontinue it at any time. This feature is for evaluation purposes only, not for production use. Itโ€™s offered as is and isnโ€™t supported, and Salesforce has no liability for any harm or damage arising out of or in connection with it. All restrictions, Salesforce reservation of rights, obligations concerning the Services, and terms for related Non-Salesforce Applications and Content apply equally to your use of this feature. You can provide feedback and suggestions for Salesforce Plugin Generator in the [issues](TODO:replace-with-link-to-github-issues) section of this repo.** +____ +# Usage +## Check Your Salesforce CLI Version +Starting with Salesforce CLI version 6.7.1, the plugin generator is offered as a core plugin and can be used out of the box. To check your Salesforce CLI version: +```sh-session +$ sfdx --version +``` + +## Generate a Salesforce CLI Plugin +Create and configure your own plugin for the Salesforce CLI. + +1. **Run `sfdx plugins:generate yourPluginName`.** + + Unless you include the `--defaults` flag, you are prompted for information that's used to populate your new plugin. Answer the questions, or press Enter to use the default values. + ```sh-session + $ sfdx plugins:generate yourPluginName + ? npm package name (yourPluginName) + ... + Created yourPluginName in $HOME//yourPluginName: + ``` + + The generator scaffolds a new sfdx plugin and installs the plugin's npm package dependencies. + +2. **Change directories into the newly created plugin directory.** + ```sh-session + $ cd yourPluginName + ``` + The new plugin contains an example `hello:org` command. You can find the code for that command at `yourPluginName/src/commands/hello/org.ts`. + +3. **Run your `hello:org` command.** + + This can be done in one of two ways: + * Link your new plugin to the Salesforce CLI. This installs the plugin in the Salesforce CLI by creating a symlink to the `yourPluginName` directory. + ```sh-shell + $ sfdx plugins:link + ``` + With the plugin linked, you can see command details by adding the `-h` | `--help` flag. + ```sh-session + $ sfdx hello:org --help + USAGE + $ sfdx hello:org [FILE] + + OPTIONS + -f, --force + -n, --name=name name to print + -u, --targetusername=targetusername username or alias for the target org; overrides default target org + -v, --targetdevhubusername=targetdevhubusername username or alias for the dev hub org; overrides default dev hub org + --apiversion=apiversion override the api version used for api requests made by this command + --json format output as json + --loglevel=(trace|debug|info|warn|error|fatal) logging level for this command invocation + + EXAMPLES + $ sfdx hello:org --targetusername myOrg@example.com --targetdevhubusername devhub@org.com + Hello world! This is org: MyOrg and I will be around until Tue Mar 20 2018! + My hub org id is: 00Dxx000000001234 + + $ sfdx hello:org --name myname --targetusername myOrg@example.com + Hello myname! This is org: MyOrg and I will be around until Tue Mar 20 2018! + ``` + + * Alternatively, you can run the `hello:org` command without linking it to the Salesforce CLI by using the provided `bin/run` script. + ```sh-session + $ bin/run hello:org --help + USAGE + $ sfdx hello:org [FILE] + + OPTIONS + -f, --force + -n, --name=name name to print + -u, --targetusername=targetusername username or alias for the target org; overrides default target org + -v, --targetdevhubusername=targetdevhubusername username or alias for the dev hub org; overrides default dev hub org + --apiversion=apiversion override the api version used for api requests made by this command + --json format output as json + --loglevel=(trace|debug|info|warn|error|fatal) logging level for this command invocation + + EXAMPLES + $ sfdx hello:org --targetusername myOrg@example.com --targetdevhubusername devhub@org.com + Hello world! This is org: MyOrg and I will be around until Tue Mar 20 2018! + My hub org id is: 00Dxx000000001234 + + $ sfdx hello:org --name myname --targetusername myOrg@example.com + Hello myname! This is org: MyOrg and I will be around until Tue Mar 20 2018! + ``` + +Now you are ready to develop your own commands! + + +# Salesforce CLI Plugin Development +The generated `hello:org` command extends [sfdx-command](TODO:add-link), which in turn extends [oclif/command](https://github.com/oclif/command). When you build your own commands, you extend `sfdx-command` too. + +`sfdx-command` comes packed with functionality to speed up your command development and interact more easily with Salesforce DX projects and Salesforce orgs. `sfdx-command` uses features of [sfdx-core](TODO:add-link), which exposes Salesforce API functionality that's useful in command development. See these libraries' documentation pages for a full list of features. + +## Features +The `hello:org` command highlights a small subset of the features available through [sfdx-command](TODO:add-link), [sfdx-core](TODO:add-link), and [oclif](https://github.com/oclif/command). You can find the code for the `hello:org` command at `yourPluginName/src/commands/hello/org.ts`. + +### Command Parameters +Add standard and custom parameters to your commands. + +#### Automatic Parameter Generation +`sfdx-command` automatically enables the `--json` and `--loglevel` flags on every command to make continuous integration setup and debugging easier. + +#### Optional Parameter Generation + +`sfdx-command` also includes functionality to help you set up connections with Salesforce orgs. For example, to enable the `--targetusername` parameter for your command: +```js +protected static requiresUsername = true; +``` + +Now, the command can access the org that has a specified target username. +```js +public async run(): Promise { + const org = this.org; +} +``` + +[TODO: link to sfdx-command flag docs](). + +#### Custom Parameters +In addition to the `sfdx-command` parameters, you can specify your own custom parameters by setting the `flagsConfig` variable. + +```js +protected static flagsConfig = { + // flag with a value (-n, --name=VALUE) + name: flags.string({char: 'n', description: messages.getMessage('nameFlagDescription')}), + force: flags.boolean({char: 'f'}) +}; +``` +[TODO: link to custom flag configuration documentation](). + +### Message Loading +The [sfdx-core](TODO: add link to sfdx-core messaging docs) APIs provide a framework for handling command messaging. +```js +core.Messages.importMessagesDirectory(pathToPluginRootDirectory); +const messages = core.Messages.loadMessages('yourPluginName', 'org'); +``` + +### Topics +As you add more commands to your CLI plugin, it can also be useful to nest your commands within topics. In the case of the generated plugin, `hello` is the topic and `org` is the command name. This structure was created by placing the `org.ts` file in the `hello` subdirectory. ``` package.json src/ โ””โ”€โ”€ commands/ - ย ย  โ”œโ”€โ”€ create.ts - ย ย  โ””โ”€โ”€ destroy.ts -``` - -Multi-command CLIs may also include [plugins](https://oclif.io/docs/plugins.html). - -# ๐Ÿ— Usage - -Creating a single-command CLI: - -```sh-session -$ npx oclif single mynewcli -? npm package name (mynewcli): mynewcli -$ cd mynewcli -$ ./bin/run -hello world from ./src/index.js! -``` - -Creating a multi-command CLI: - -```sh-session -$ npx oclif multi mynewcli -? npm package name (mynewcli): mynewcli -$ cd mynewcli -$ ./bin/run --version -mynewcli/0.0.0 darwin-x64 node-v9.5.0 -$ ./bin/run --help -USAGE - $ mynewcli [COMMAND] - -COMMANDS - hello - help display help for mynewcli - -$ ./bin/run hello -hello world from ./src/hello.js! -``` - -# ๐Ÿ“š Examples - -* TypeScript - * [Multi-command CLI](https://github.com/oclif/example-multi-ts) - * [Single-command CLI](https://github.com/oclif/example-single-ts) - * [Multi-command CLI Plugin](https://github.com/oclif/example-single-ts) -* JavaScript - * [Multi-command CLI](https://github.com/oclif/example-multi-js) - * [Single-command CLI](https://github.com/oclif/example-single-js) - * [Multi-command CLI Plugin](https://github.com/oclif/example-plugin-js) - -# ๐Ÿ”จ Commands - - -* [oclif command NAME](#oclif-command-name) -* [oclif help [COMMAND]](#oclif-help-command) -* [oclif hook NAME](#oclif-hook-name) -* [oclif multi [PATH]](#oclif-multi-path) -* [oclif plugin [PATH]](#oclif-plugin-path) -* [oclif single [PATH]](#oclif-single-path) - -## oclif command NAME - -add a command to an existing CLI or plugin - -``` -USAGE - $ oclif command NAME - -ARGUMENTS - NAME name of command - -OPTIONS - --defaults use defaults for every setting - --force overwrite existing files -``` - -_See code: [src/commands/command.ts](https://github.com/oclif/oclif/blob/v1.7.13/src/commands/command.ts)_ - -## oclif help [COMMAND] - -display help for oclif - -``` -USAGE - $ oclif help [COMMAND] - -ARGUMENTS - COMMAND command to show help for - -OPTIONS - --all see all commands in CLI -``` - -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v1.2.1/src/commands/help.ts)_ - -## oclif hook NAME - -add a hook to an existing CLI or plugin - -``` -USAGE - $ oclif hook NAME - -ARGUMENTS - NAME name of hook (snake_case) - -OPTIONS - --defaults use defaults for every setting - --event=event [default: init] event to run hook on - --force overwrite existing files -``` - -_See code: [src/commands/hook.ts](https://github.com/oclif/oclif/blob/v1.7.13/src/commands/hook.ts)_ - -## oclif multi [PATH] - -generate a new multi-command CLI - -``` -USAGE - $ oclif multi [PATH] - -ARGUMENTS - PATH path to project, defaults to current directory - -OPTIONS - --defaults use defaults for every setting - --force overwrite existing files - --options=options (yarn|typescript|tslint|semantic-release|mocha) -``` - -_See code: [src/commands/multi.ts](https://github.com/oclif/oclif/blob/v1.7.13/src/commands/multi.ts)_ - -## oclif plugin [PATH] - -create a new CLI plugin - -``` -USAGE - $ oclif plugin [PATH] - -ARGUMENTS - PATH path to project, defaults to current directory - -OPTIONS - --defaults use defaults for every setting - --force overwrite existing files - --options=options (yarn|typescript|tslint|semantic-release|mocha) -``` - -_See code: [src/commands/plugin.ts](https://github.com/oclif/oclif/blob/v1.7.13/src/commands/plugin.ts)_ - -## oclif single [PATH] - -generate a new single-command CLI - -``` -USAGE - $ oclif single [PATH] - -ARGUMENTS - PATH path to project, defaults to current directory - -OPTIONS - --defaults use defaults for every setting - --force overwrite existing files - --options=options (yarn|typescript|tslint|semantic-release|mocha) -``` - -_See code: [src/commands/single.ts](https://github.com/oclif/oclif/blob/v1.7.13/src/commands/single.ts)_ - - -# ๐Ÿญ Related Repositories - -* [@oclif/command](https://github.com/oclif/command) - Base command for oclif. This can be used directly without the generator. -* [@oclif/config](https://github.com/oclif/config) - Most of the core setup for oclif lives here. -* [@oclif/errors](https://github.com/oclif/errors) - Renders and logs errors from commands. -* [@oclif/cli-ux](https://github.com/oclif/cli-ux) - Library for common CLI UI utilities. -* [@oclif/test](https://github.com/oclif/test) - Test helper for oclif. - -# ๐Ÿฆ” Learn More - -* [Salesforce Release Announcement](https://engineering.salesforce.com/open-sourcing-oclif-the-cli-framework-that-powers-our-clis-21fbda99d33a) -* [Heroku Release Announcement](https://blog.heroku.com/open-cli-framework) - -# ๐Ÿ“ฃ Feedback - -If you have any suggestions or just want to let us know what you think of oclif, send us a message at + โ””โ”€โ”€ hello/ + โ””โ”€โ”€ org.ts +``` +See [oclif/oclif#-topics](https://github.com/oclif/oclif#-topics) for more information on how to structure your directories to utilize topics. + +## Important Note for Plugin Command Developers +Because this is a TypeScript project, you need to compile the changes you make to your commands before running the commands. +* If you linked your plugin to the Salesforce CLI, to compile your code and update the `.oclif.manifest.json` file that is consumed by the Salesforce CLI, run: + ```sh-session + yarn run prepare + ``` + +* If you use the `bin/run` script to run your commands, to compile your changes, run: + ```sh-session + yarn run build + ``` + +## Debugging your plugin: +We recommend using the Visual Studio Code (VS Code) IDE for your plugin development. Included in the `.vscode` directory of the generated plugin is a `launch.json` config file, which allows you to attach a debugger to the node process when running your commands. + +To debug the `hello:org` command from the `myNewPlugin` directory: +1. Start the inspector + + * If you linked your plugin to the sfdx cli, call your command with the `dev-suspend` switch: + ```sh-session + $ sfdx hello:org -u myOrg@example.com --dev-suspend + ``` + + * Alternatively, to call your command using the `bin/run` script, set the `NODE_OPTIONS` environment variable to `--inspect-brk` when starting the debugger: + ```sh-session + $ NODE_OPTIONS=--inspect-brk bin/run hello:org -u myOrg@example.com + ``` + +2. Set some breakpoints in your command code +3. Click on the Debug icon in the Activity Bar on the side of VS Code to open up the Debug view. +4. In the upper left hand corner of VS Code, verify that the "Attach to Remote" launch configuration has been chosen. +5. Hit the green play button to the left of the "Attach to Remote" launch configuration window. The debugger should now be suspended on the first line of the program. +6. Hit the green play button at the top middle of VS Code (this play button will be to the right of the play button that you clicked in step #5). +

+Congrats, you are now debugging! + +# Plugin Generator Development +To make changes to the plugin generator, follow these instructions. +======= + +Note: Only Node 8+ is supported. If you are new to Node.js, use nvm to install node. + +1. Start by cloning the repo. + ```sh-session + $ git clone TODO:update-with-repo + ``` +2. Change directories into the cloned repo. + ```sh-session + $ cd TODO:update-with-repo-name + ``` +3. If you don't have Node.js version 8 or above installed, install it now. + ```sh-session + $ nvm install v8.9.4 + ``` +4. Install the Yarn package manager. + ```sh-session + $ npm install -g yarn + ``` +5. Install the plugin generator. + ```sh-session + $ yarn install + ``` +6. Compile the TypeScript code. + ```sh-session + $ yarn run build + ``` +7. Now you are ready to run the plugins:generate command and make any changes to the generator. + ```sh-session + $ bin/run plugins:generate yourPluginName + ``` + +# Related Docs and Repositories +* [salesforcedx/sfdx-command](TODO:add-link) - Base Salesforce CLI command +* [salesforcedx/sfdx-core](TODO:add-link) - Helper API for working with a Salesforce DX project and managing Salesforce orgs +* [@oclif/command](https://github.com/oclif/command) - Base command for oclif; this can be used directly without the generator +* [@oclif/config](https://github.com/oclif/config) - Most of the core setup for oclif lives here +* [@oclif/errors](https://github.com/oclif/errors) - Renders and logs errors from commands +* [@oclif/cli-ux](https://github.com/oclif/cli-ux) - Library for common CLI UI utilities +* [@oclif/test](https://github.com/oclif/test) - Test helper for oclif \ No newline at end of file diff --git a/package.json b/package.json index 77684df..1a2d99e 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { - "name": "oclif", - "description": "oclif: create your own CLI", - "version": "1.7.13", - "author": "Jeff Dickey @jdxcode", + "name": "@salesforce/plugin-generator", + "description": "create your own sfdx plugin", + "version": "0.0.5", + "author": "ALM - CI", "bin": "./bin/run", - "bugs": "https://github.com/oclif/oclif/issues", + "bugs": "", "dependencies": { "@oclif/command": "^1.4.6", "@oclif/config": "^1.3.61", @@ -52,9 +52,10 @@ ".oclif.manifest.json", "/bin", "/lib", - "/templates" + "/templates", + "/messages" ], - "homepage": "https://github.com/oclif/oclif", + "homepage": "", "keywords": [ "oclif" ], @@ -75,6 +76,7 @@ "lint": "nps lint", "postpublish": "rm .oclif.manifest.json", "posttest": "yarn run lint", + "prepack": "oclif-dev manifest", "prepublishOnly": "yarn run build && oclif-dev manifest", "version": "oclif-dev readme && oclif-dev manifest && git add README.md", "test": "nps test" diff --git a/sfdx-ci.yaml b/sfdx-ci.yaml new file mode 100644 index 0000000..1900089 --- /dev/null +++ b/sfdx-ci.yaml @@ -0,0 +1,4 @@ +jobs: + - name: publish + skipTests: true + - name: promote diff --git a/src/command_base.ts b/src/command_base.ts index ec9491b..27e3fe7 100644 --- a/src/command_base.ts +++ b/src/command_base.ts @@ -7,11 +7,11 @@ export default abstract class CommandBase extends Command { env.register( require.resolve(`./generators/${type}`), - `oclif:${type}` + `sfdx:${type}` ) await new Promise((resolve, reject) => { - env.run(`oclif:${type}`, generatorOptions, (err: Error, results: any) => { + env.run(`sfdx:${type}`, generatorOptions, (err: Error, results: any) => { if (err) reject(err) else resolve(results) }) diff --git a/src/commands/command.ts b/src/commands/command.ts index 9f78b4b..f824d47 100644 --- a/src/commands/command.ts +++ b/src/commands/command.ts @@ -9,6 +9,7 @@ export interface Options { } export default abstract class AppCommand extends Base { + static hidden = true static description = 'add a command to an existing CLI or plugin' static flags = { diff --git a/src/commands/multi.ts b/src/commands/multi.ts index 759a1bd..144265f 100644 --- a/src/commands/multi.ts +++ b/src/commands/multi.ts @@ -1,6 +1,7 @@ import AppCommand from '../app_command' export default class extends AppCommand { + static hidden = true static description = 'generate a new multi-command CLI' type = 'multi' } diff --git a/src/commands/plugin.ts b/src/commands/plugin.ts index 7d55a9f..51cdbcd 100644 --- a/src/commands/plugin.ts +++ b/src/commands/plugin.ts @@ -1,6 +1,7 @@ import AppCommand from '../app_command' export default class extends AppCommand { + static hidden = true static description = 'create a new CLI plugin' type = 'plugin' } diff --git a/src/commands/plugins/generate.ts b/src/commands/plugins/generate.ts new file mode 100644 index 0000000..cfd08c3 --- /dev/null +++ b/src/commands/plugins/generate.ts @@ -0,0 +1,28 @@ +import Base from '../../command_base' +import {flags} from '@oclif/command' + +export default class Generate extends Base { + static flags = { + defaults: flags.boolean({description: 'use defaults for every setting'}), + force: flags.boolean({description: 'overwrite existing files'}), + } + + static args = [ + {name: 'path', required: false} + ] + + static description = 'create a new sfdx-cli plugin' + type = 'sfdx-plugin' + + async run() { + const {flags, args} = this.parse(Generate) + + await super.generate('app', { + type: this.type, + path: args.path, + defaults: flags.defaults, + force: flags.force, + options: [] + }) + } +} diff --git a/src/commands/single.ts b/src/commands/single.ts index 0a5e6f6..bc05cca 100644 --- a/src/commands/single.ts +++ b/src/commands/single.ts @@ -1,6 +1,7 @@ import AppCommand from '../app_command' export default class extends AppCommand { + static hidden = true static description = 'generate a new single-command CLI' type = 'single' } diff --git a/src/generators/app.ts b/src/generators/app.ts index ebb2dd2..7206856 100644 --- a/src/generators/app.ts +++ b/src/generators/app.ts @@ -43,7 +43,7 @@ class App extends Generator { yarn: boolean } args!: {[k: string]: string} - type: 'single' | 'multi' | 'plugin' | 'base' + type: 'single' | 'multi' | 'plugin' | 'base' | 'sfdx-plugin' path: string pjson: any githubUser: string | undefined @@ -102,6 +102,9 @@ class App extends Generator { case 'multi': msg = 'Time to build a multi-command CLI with oclif!' break + case 'sfdx-plugin': + msg = 'Time to build an sfdx-cli plugin!' + break default: msg = `Time to build a oclif ${this.type}!` } @@ -223,6 +226,7 @@ class App extends Generator { {name: 'semantic-release (automated version management)', value: 'semantic-release', checked: this.options['semantic-release']} ], filter: ((arr: string[]) => _.keyBy(arr)) as any, + when: this.type !== 'sfdx-plugin' }, // { // type: 'string', @@ -234,7 +238,8 @@ class App extends Generator { ]) as any } debug(this.answers) - this.options = this.answers.options + const sfdxPluginOptions = {typescript: true, mocha: true, 'semantic-release': false} + this.options = this.type === 'sfdx-plugin' ? sfdxPluginOptions : this.answers.options this.ts = this.options.typescript this.tslint = this.options.tslint this.yarn = this.options.yarn @@ -268,15 +273,32 @@ class App extends Generator { this.pjson.scripts.build = 'rm -rf lib && tsc' this.pjson.scripts.prepublishOnly = `${npm} run build` } - if (['plugin', 'multi'].includes(this.type)) { + if (['sfdx-plugin', 'plugin', 'multi'].includes(this.type)) { this.pjson.scripts.prepublishOnly = nps.series(this.pjson.scripts.prepublishOnly, 'oclif-dev manifest') if (this.semantic_release) this.pjson.scripts.prepublishOnly = nps.series(this.pjson.scripts.prepublishOnly, 'oclif-dev readme') this.pjson.scripts.version = nps.series('oclif-dev readme', 'git add README.md') this.pjson.scripts.clean = 'rm -f .oclif.manifest.json' this.pjson.scripts.postpublish = this.pjson.scripts.preversion = `${npm} run clean` this.pjson.files.push('.oclif.manifest.json') + if (this.type === 'sfdx-plugin') { + this.pjson.files.push('/messages') + this.pjson.scripts.prepare = this.pjson.scripts.prepublishOnly + } + } + + let keywords + switch (this.type) { + case 'sfdx-plugin': + keywords = 'sfdx-plugin' + break + case 'plugin': + keywords = 'oclif-plugin' + break + default: + keywords = 'oclif' } - this.pjson.keywords = defaults.keywords || [this.type === 'plugin' ? 'oclif-plugin' : 'oclif'] + + this.pjson.keywords = defaults.keywords || [keywords] this.pjson.homepage = defaults.homepage || `https://github.com/${this.pjson.repository}` this.pjson.bugs = defaults.bugs || `https://github.com/${this.pjson.repository}/issues` @@ -288,7 +310,7 @@ class App extends Generator { } else if (this.type === 'plugin') { this.pjson.oclif.bin = 'oclif-example' } - if (this.type !== 'plugin') { + if (this.type !== 'plugin' && this.type !== 'sfdx-plugin') { this.pjson.main = defaults.main || (this.ts ? 'lib/index.js' : 'src/index.js') if (this.ts) { this.pjson.types = defaults.types || 'lib/index.d.ts' @@ -302,6 +324,7 @@ class App extends Generator { switch (this.type) { case 'multi': case 'plugin': + case 'sfdx-plugin': this.pjson.oclif = { commands: `./${this.ts ? 'lib' : 'src'}/commands`, // hooks: {init: `./${this.ts ? 'lib' : 'src'}/hooks/init`}, @@ -310,7 +333,7 @@ class App extends Generator { break default: } - if (this.type === 'plugin' && !this.pjson.oclif.devPlugins) { + if ((this.type === 'plugin' || this.type === 'sfdx-plugin') && !this.pjson.oclif.devPlugins) { this.pjson.oclif.devPlugins = [ '@oclif/plugin-help', ] @@ -331,7 +354,11 @@ class App extends Generator { } this.fs.copyTpl(this.templatePath('tsconfig.json'), this.destinationPath('tsconfig.json'), this) if (this.mocha) { - this.fs.copyTpl(this.templatePath('test/tsconfig.json'), this.destinationPath('test/tsconfig.json'), this) + if (this.type === 'sfdx-plugin') { + this.fs.copyTpl(this.templatePath('sfdxPlugin/test/tsconfig.json'), this.destinationPath('test/tsconfig.json'), this) + } else { + this.fs.copyTpl(this.templatePath('test/tsconfig.json'), this.destinationPath('test/tsconfig.json'), this) + } } } if (this.mocha && !this.fs.exists('test')) { @@ -343,6 +370,7 @@ class App extends Generator { } if (_.isEmpty(this.pjson.oclif)) delete this.pjson.oclif this.pjson.files = _.uniq((this.pjson.files || []).sort()) + this.fs.writeJSON(this.destinationPath('./package.json'), sortPjson(this.pjson)) this.fs.copyTpl(this.templatePath('editorconfig'), this.destinationPath('.editorconfig'), this) this.fs.copyTpl(this.templatePath('scripts/greenkeeper'), this.destinationPath('.circleci/greenkeeper'), this) @@ -350,7 +378,7 @@ class App extends Generator { // this.fs.copyTpl(this.templatePath('scripts/release'), this.destinationPath('.circleci/release'), this) // } // this.fs.copyTpl(this.templatePath('scripts/setup_git'), this.destinationPath('.circleci/setup_git'), this) - this.fs.copyTpl(this.templatePath('README.md.ejs'), this.destinationPath('README.md'), this) + this.fs.copyTpl(this.templatePath('circle.yml.ejs'), this.destinationPath('.circleci/config.yml'), this) this.fs.copyTpl(this.templatePath('appveyor.yml.ejs'), this.destinationPath('appveyor.yml'), this) if (this.pjson.license === 'MIT' && (this.pjson.repository.startsWith('oclif') || this.pjson.repository.startsWith('heroku'))) { @@ -362,9 +390,12 @@ class App extends Generator { this.fs.copyTpl(this.templatePath('gitattributes'), this.destinationPath('.gitattributes'), this) this.fs.write(this.destinationPath('.gitignore'), this._gitignore()) - this.fs.copyTpl(this.templatePath('eslintrc'), this.destinationPath('.eslintrc'), this) - const eslintignore = this._eslintignore() - if (eslintignore.trim()) this.fs.write(this.destinationPath('.eslintignore'), this._eslintignore()) + if (this.type !== 'sfdx-plugin') { + this.fs.copyTpl(this.templatePath('README.md.ejs'), this.destinationPath('README.md'), this) + this.fs.copyTpl(this.templatePath('eslintrc'), this.destinationPath('.eslintrc'), this) + const eslintignore = this._eslintignore() + if (eslintignore.trim()) this.fs.write(this.destinationPath('.eslintignore'), this._eslintignore()) + } switch (this.type) { case 'single': @@ -373,6 +404,9 @@ class App extends Generator { case 'plugin': this._writePlugin() break + case 'sfdx-plugin': + this._writeSfdxPlugin() + break case 'multi': this._writeMulti() break @@ -404,6 +438,21 @@ class App extends Generator { 'globby', ) break + case 'sfdx-plugin': + dependencies.push( + '@oclif/command', + '@oclif/config', + '@oclif/errors', + '@salesforce/command', + ) + devDependencies.push( + '@oclif/dev-cli', + '@oclif/plugin-help', + 'globby', + '@salesforce/dev-config', + 'sinon', + ) + break case 'multi': dependencies.push( '@oclif/config', @@ -456,7 +505,7 @@ class App extends Generator { install(devDependencies, {...yarnOpts, ...dev, ignoreScripts: true}), install(dependencies, yarnOpts), ]).then(() => { - if (['plugin', 'multi'].includes(this.type)) { + if (['sfdx-plugin', 'plugin', 'multi'].includes(this.type)) { this.spawnCommandSync(path.join('.', 'node_modules/.bin/oclif-dev'), ['readme']) } console.log(`\nCreated ${this.pjson.name} in ${this.destinationRoot()}`) @@ -518,6 +567,39 @@ class App extends Generator { } } + private _writeSfdxPlugin() { + const sfdxExampleCommand = 'org' + const topic = 'hello' + const bin = this._bin + const cmd = `${bin} ${sfdxExampleCommand}` + const opts = {...this as any, _, bin, cmd} + this.fs.copyTpl(this.templatePath('plugin/bin/run'), this.destinationPath('bin/run'), opts) + this.fs.copyTpl(this.templatePath('bin/run.cmd'), this.destinationPath('bin/run.cmd'), opts) + this.fs.copyTpl(this.templatePath('sfdxPlugin/README.md.ejs'), this.destinationPath('README.md'), this) + this.fs.copy(this.templatePath('.images/vscodeScreenshot.png'), this.destinationPath('.images/vscodeScreenshot.png'), this) + if (!fs.existsSync('src/commands')) { + this.fs.copyTpl(this.templatePath(`src/sfdxCommand.${this._ext}.ejs`), this.destinationPath(`src/commands/${topic}/${sfdxExampleCommand}.${this._ext}`), { + ...opts, + pluginName: this.pjson.name, + commandName: sfdxExampleCommand, + topicName: topic + }) + } + this.fs.copyTpl(this.templatePath('sfdxPlugin/src/index.ts'), this.destinationPath('src/index.ts'), opts) + if (this.mocha && !fs.existsSync('test')) { + this.fs.copyTpl(this.templatePath(`sfdxPlugin/test/command.test.${this._ext}.ejs`), this.destinationPath(`test/commands/${topic}/${sfdxExampleCommand}.test.${this._ext}`), + {...opts, name: sfdxExampleCommand, topic}) + } + + if (!fs.existsSync('messages/messages.json')) { + this.fs.copyTpl(this.templatePath('messages/messages.json'), this.destinationPath(`messages/${sfdxExampleCommand}.json`), this) + } + + if (!fs.existsSync('.vscode/launch.json')) { + this.fs.copyTpl(this.templatePath('.vscode/launch.json'), this.destinationPath(`.vscode/launch.json`), this) + } + } + private _writeSingle() { const bin = this._bin const opts = {...this as any, _, bin, cmd: bin, name: this.pjson.name} diff --git a/templates/.images/vscodeScreenshot.png b/templates/.images/vscodeScreenshot.png new file mode 100644 index 0000000..4b7206a Binary files /dev/null and b/templates/.images/vscodeScreenshot.png differ diff --git a/templates/.vscode/launch.json b/templates/.vscode/launch.json new file mode 100644 index 0000000..08affd5 --- /dev/null +++ b/templates/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Attach to Remote", + "address": "127.0.0.1", + "port": 9229, + "localRoot": "${workspaceFolder}" + } + ] +} diff --git a/templates/messages/messages.json b/templates/messages/messages.json new file mode 100644 index 0000000..19bf8e6 --- /dev/null +++ b/templates/messages/messages.json @@ -0,0 +1,4 @@ +{ + "commandDescription": "Prints a greeting and your org id(s)!", + "nameFlagDescription": "name to print" +} diff --git a/templates/sfdxPlugin/README.md.ejs b/templates/sfdxPlugin/README.md.ejs new file mode 100644 index 0000000..85d5a89 --- /dev/null +++ b/templates/sfdxPlugin/README.md.ejs @@ -0,0 +1,42 @@ +<%= pjson.name %> +<%= '='.repeat(pjson.name.length) %> + +<%= pjson.description %> + +[![Version](https://img.shields.io/npm/v/<%= pjson.name %>.svg)](https://npmjs.org/package/<%= pjson.name %>) +[![CircleCI](https://circleci.com/gh/<%= repository %>/tree/master.svg?style=shield)](https://circleci.com/gh/<%= repository %>/tree/master) +[![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/<%= repository %>?branch=master&svg=true)](https://ci.appveyor.com/project/heroku/<%= repository.split('/').pop() %>/branch/master) +[![Codecov](https://codecov.io/gh/<%= repository %>/branch/master/graph/badge.svg)](https://codecov.io/gh/<%= repository %>) +[![Greenkeeper](https://badges.greenkeeper.io/<%= repository %>.svg)](https://greenkeeper.io/) +[![Known Vulnerabilities](https://snyk.io/test/github/<%= repository %>/badge.svg)](https://snyk.io/test/github/<%= repository %>) +[![Downloads/week](https://img.shields.io/npm/dw/<%= pjson.name %>.svg)](https://npmjs.org/package/<%= pjson.name %>) +[![License](https://img.shields.io/npm/l/<%= pjson.name %>.svg)](https://github.com/<%= repository %>/blob/master/package.json) + + + + + + +# Debugging your plugin +We recommend using the Visual Studio Code (VS Code) IDE for your plugin development. Included in the `.vscode` directory of this plugin is a `launch.json` config file, which allows you to attach a debugger to the node process when running your commands. + +To debug the `hello:org` command: +1. Start the inspector + +If you linked your plugin to the sfdx cli, call your command with the `dev-suspend` switch: +```sh-session +$ sfdx hello:org -u myOrg@example.com --dev-suspend +``` + +Alternatively, to call your command using the `bin/run` script, set the `NODE_OPTIONS` environment variable to `--inspect-brk` when starting the debugger: +```sh-session +$ NODE_OPTIONS=--inspect-brk bin/run hello:org -u myOrg@example.com +``` + +2. Set some breakpoints in your command code +3. Click on the Debug icon in the Activity Bar on the side of VS Code to open up the Debug view. +4. In the upper left hand corner of VS Code, verify that the "Attach to Remote" launch configuration has been chosen. +5. Hit the green play button to the left of the "Attach to Remote" launch configuration window. The debugger should now be suspended on the first line of the program. +6. Hit the green play button at the top middle of VS Code (this play button will be to the right of the play button that you clicked in step #5). +

+Congrats, you are debugging! diff --git a/templates/sfdxPlugin/src/index.ts b/templates/sfdxPlugin/src/index.ts new file mode 100644 index 0000000..ff8b4c5 --- /dev/null +++ b/templates/sfdxPlugin/src/index.ts @@ -0,0 +1 @@ +export default {}; diff --git a/templates/sfdxPlugin/test/command.test.ts.ejs b/templates/sfdxPlugin/test/command.test.ts.ejs new file mode 100644 index 0000000..45ced07 --- /dev/null +++ b/templates/sfdxPlugin/test/command.test.ts.ejs @@ -0,0 +1,14 @@ +import { expect, test } from '@salesforce/command/dist/test'; + +describe('<%- topic %>:<%- name %>', () => { + test + .withOrg({ username: 'test@org.com' }, true) + .withConnectionRequest(function() { + return Promise.resolve({ records: [ { Name: 'Super Awesome Org', TrialExpirationDate: '2018-03-20T23:24:11.000+0000'}]}); + }) + .stdout() + .command(['<%- topic %>:<%- name %>', '--targetusername', 'test@org.com']) + .it('runs <%- topic %>:<%- name %> --targetusername test@org.com', (ctx) => { + expect(ctx.stdout).to.contain('Hello world! This is org: Super Awesome Org and I will be around until Tue Mar 20 2018!'); + }); +}); diff --git a/templates/sfdxPlugin/test/tsconfig.json b/templates/sfdxPlugin/test/tsconfig.json new file mode 100644 index 0000000..4f7a5ce --- /dev/null +++ b/templates/sfdxPlugin/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig" +} + diff --git a/templates/src/sfdxCommand.ts.ejs b/templates/src/sfdxCommand.ts.ejs new file mode 100644 index 0000000..e54cc14 --- /dev/null +++ b/templates/src/sfdxCommand.ts.ejs @@ -0,0 +1,80 @@ +import {flags} from '@oclif/command'; +import {join} from 'path'; +import {SfdxCommand, core} from '@salesforce/command'; +<%_ const klass = _.upperFirst(_.camelCase(commandName)) _%> + +core.Messages.importMessagesDirectory(join(__dirname, '..', '..', '..')); +const messages = core.Messages.loadMessages('<%- pluginName %>', '<%- commandName %>'); + +export default class <%- klass %> extends SfdxCommand { + + public static description = messages.getMessage('commandDescription'); + + public static examples = [ + `$ sfdx <%- topicName %>:<%- commandName %> --targetusername myOrg@example.com --targetdevhubusername devhub@org.com + Hello world! This is org: MyOrg and I will be around until Tue Mar 20 2018! + My hub org id is: 00Dxx000000001234 + `, + `$ sfdx <%- topicName %>:<%- commandName %> --name myname --targetusername myOrg@example.com + Hello myname! This is org: MyOrg and I will be around until Tue Mar 20 2018! + ` + ]; + + public static args = [{name: 'file'}]; + + protected static flagsConfig = { + // flag with a value (-n, --name=VALUE) + name: flags.string({char: 'n', description: messages.getMessage('nameFlagDescription')}), + force: flags.boolean({char: 'f'}) + }; + + // Comment this out if your command does not require an org username + protected static requiresUsername = true; + + // Comment this out if your command does not support a hub org username + protected static supportsDevhubUsername = true; + + // Set this to true if your command requires a project workspace; 'requiresProject' is false by default + protected static requiresProject = false; + + public async run(): Promise { // tslint:disable-line:no-any + const name = this.flags.name || 'world'; + + // this.org is guaranteed because requiresUsername=true, as opposed to supportsUsername + const conn = this.org.getConnection(); + const query = 'Select Name, TrialExpirationDate from Organization'; + + // The type we are querying for + interface Organization { + Name: string; + TrialExpirationDate: string; + } + + // Query the org + const result = await conn.query(query); + + // Organization always only returns one result + const orgName = result.records[0].Name; + const trialExpirationDate = result.records[0].TrialExpirationDate; + + let outputString = `Hello ${name}! This is org: ${orgName}`; + if (trialExpirationDate) { + const date = new Date(trialExpirationDate).toDateString(); + outputString = `${outputString} and I will be around until ${date}!`; + } + this.ux.log(outputString); + + // this.hubOrg is NOT guaranteed because supportsHubOrgUsername=true, as opposed to requiresHubOrgUsername. + if (this.hubOrg) { + const hubOrgId = this.hubOrg.getOrgId(); + this.ux.log(`My hub org id is: ${hubOrgId}`); + } + + if (this.flags.force && this.args.file) { + this.ux.log(`You input --force and --file: ${this.args.file}`); + } + + // Return an object to be displayed with --json + return { orgId: this.org.getOrgId(), outputString }; + } +} diff --git a/templates/tsconfig.json b/templates/tsconfig.json index c6454f7..3bce77c 100644 --- a/templates/tsconfig.json +++ b/templates/tsconfig.json @@ -1,16 +1,14 @@ { + "extends": "./node_modules/@salesforce/dev-config/tsconfig", "compilerOptions": { - "declaration": true, - "forceConsistentCasingInFileNames": true, - "importHelpers": true, - "module": "commonjs", "outDir": "./lib", - "pretty": true, "rootDirs": [ "./src" ], - "strict": true, - "target": "es2017" + "baseUrl": "./", + "paths" : { + "*" : ["./node_modules/@salesforce/core/typings/*"] + } }, "include": [ "./src/**/*" diff --git a/templates/tslint.json b/templates/tslint.json index f570354..313c5cf 100644 --- a/templates/tslint.json +++ b/templates/tslint.json @@ -1,3 +1,3 @@ { - "extends": "@oclif/tslint" + "extends": "@salesforce/dev-config/tslint" } diff --git a/tsconfig.json b/tsconfig.json index c6454f7..53a1647 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ "rootDirs": [ "./src" ], - "strict": true, +// "strict": true, "target": "es2017" }, "include": [ diff --git a/yarn.lock b/yarn.lock index 5e5bd77..4dac9d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,17 +2,17 @@ # yarn lockfile v1 -"@fimbul/bifrost@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@fimbul/bifrost/-/bifrost-0.5.0.tgz#60e96911fa61c5552eebfc1fbf1738e3afeecf23" +"@fimbul/bifrost@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@fimbul/bifrost/-/bifrost-0.6.0.tgz#5150302b63e1bd37ff95f561c3605949cb7e3770" dependencies: - "@fimbul/ymir" "^0.4.0" + "@fimbul/ymir" "^0.6.0" get-caller-file "^1.0.2" tslib "^1.8.1" -"@fimbul/ymir@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@fimbul/ymir/-/ymir-0.4.0.tgz#5d2aeb86f1b257f778d501bbf3b811d2ba3dd3bc" +"@fimbul/ymir@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@fimbul/ymir/-/ymir-0.6.0.tgz#537cb15d361b7c993fe953b48c898ecdf4f671b8" dependencies: inversify "^4.10.0" reflect-metadata "^0.1.12" @@ -82,11 +82,11 @@ dependencies: "@heroku/linewrap" "^1.0.0" -"@oclif/plugin-help@^1.1.6", "@oclif/plugin-help@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-1.2.1.tgz#5537779e5a1cfb812d54333111c861d06771c18f" +"@oclif/plugin-help@^1.1.6", "@oclif/plugin-help@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-1.2.2.tgz#7a4846b71a6d47720b628218fdb4bafa71155de3" dependencies: - "@oclif/command" "^1.4.4" + "@oclif/command" "^1.4.6" chalk "^2.3.2" indent-string "^3.2.0" lodash.template "^4.4.0" @@ -134,8 +134,8 @@ "@types/node" "*" "@types/inquirer@*": - version "0.0.38" - resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.38.tgz#5c682b87152ebe8d759c875f2edbc56d787c6b99" + version "0.0.41" + resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.41.tgz#0c33027dcd0b0dde234e22afa454f2c75d8b30d2" dependencies: "@types/rx" "*" "@types/through" "*" @@ -149,8 +149,8 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" "@types/node@*": - version "9.6.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.0.tgz#d3480ee666df9784b1001a1872a2f6ccefb6c2d7" + version "9.6.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.2.tgz#e49ac1adb458835e95ca6487bc20f916b37aff23" "@types/normalize-package-data@*": version "2.4.0" @@ -264,8 +264,8 @@ "@types/node" "*" "@types/yeoman-generator@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/yeoman-generator/-/yeoman-generator-2.0.1.tgz#e64c43062894f463dcd0f83e43340db947eedb95" + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/yeoman-generator/-/yeoman-generator-2.0.3.tgz#f4b161ee354078b526e0901a5a5f87d4f8e085f6" dependencies: "@types/events" "*" "@types/inquirer" "*" @@ -309,8 +309,8 @@ alce@1.0.0: estraverse "~1.3.0" ansi-escapes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" @@ -401,8 +401,8 @@ async@^2.6.0: lodash "^4.14.0" atob@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" + version "2.1.0" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" babel-code-frame@^6.22.0: version "6.26.0" @@ -738,8 +738,8 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" core-js@^2.4.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + version "2.5.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.4.tgz#f2c8bf181f2a80b92f360121429ce63a2f0aeae0" core-util-is@~1.0.0: version "1.0.2" @@ -934,8 +934,8 @@ editions@^1.3.3: resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" ejs@^2.3.1: - version "2.5.7" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a" + version "2.5.8" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.8.tgz#2ab6954619f225e6193b7ac5f7c39c48fefe4380" error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.1" @@ -1078,8 +1078,8 @@ esprima@~1.0.4: resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" esquery@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: estraverse "^4.0.0" @@ -1171,8 +1171,8 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: is-extendable "^1.0.1" external-editor@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: chardet "^0.4.0" iconv-lite "^0.4.17" @@ -1836,8 +1836,8 @@ js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1: esprima "^4.0.0" json-parse-better-errors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a" + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" json-schema-traverse@^0.3.0: version "0.3.1" @@ -2565,15 +2565,15 @@ read-pkg@^3.0.0: path-type "^3.0.0" readable-stream@^2.0.2, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~2.0.0" safe-buffer "~5.1.1" - string_decoder "~1.0.3" + string_decoder "~1.1.1" util-deprecate "~1.0.1" readline-sync@^1.4.7: @@ -2609,8 +2609,8 @@ regex-not@^1.0.0, regex-not@^1.0.2: safe-regex "^1.1.0" regexpp@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.0.1.tgz#d857c3a741dce075c2848dcb019a0a975b190d43" + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" remove-trailing-separator@^1.0.1: version "1.1.0" @@ -2940,9 +2940,9 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" dependencies: safe-buffer "~5.1.0" @@ -3181,9 +3181,9 @@ tsutils@^1.4.0: version "1.9.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" -tsutils@^2.12.1, tsutils@^2.22.2: - version "2.22.2" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.22.2.tgz#0b9f3d87aa3eb95bd32d26ce2b88aa329a657951" +tsutils@^2.12.1, tsutils@^2.24.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.26.0.tgz#706240d63bcf1ae1797d1716738d6c6be0d0848b" dependencies: tslib "^1.8.1" @@ -3208,8 +3208,8 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" typescript@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836" + version "2.8.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624" union-value@^1.0.0: version "1.0.0" @@ -3387,8 +3387,8 @@ yargs@^8.0.2: yargs-parser "^7.0.0" yeoman-environment@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.5.tgz#84f22bafa84088971fe99ea85f654a3a3dd2b693" + version "2.0.6" + resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.6.tgz#ae1b21d826b363f3d637f88a7fc9ea7414cb5377" dependencies: chalk "^2.1.0" debug "^3.1.0" @@ -3439,8 +3439,8 @@ yn@^2.0.0: resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" yosay@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/yosay/-/yosay-2.0.1.tgz#078167f0365732e5c82d3f64633f9cd3a0526d2f" + version "2.0.2" + resolved "https://registry.yarnpkg.com/yosay/-/yosay-2.0.2.tgz#a7017e764cd88d64a1ae64812201de5b157adf6d" dependencies: ansi-regex "^2.0.0" ansi-styles "^3.0.0"