diff --git a/README.md b/README.md index c4dcf54..ac93bea 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,33 @@ +# Shoutem CLI + Shoutem CLI is a command line tool which helps you build Shoutem extensions. You can read more about CLI in our [documentation](http://shoutem.github.io/docs/extensions/reference/cli) + +## Local Development + +For local development there are three ways of approaching this: + +#### 1. Compiling and running from the repository + +1. Run `npm i` inside repository +2. Run `node path/to/build/shoutem.js `, where `` is the command you're testing + +After making changes to the code, you can run `rm -rf build && npm run build` to recompile and then continue using step 2 described above. + +#### 2. Editing global node_modules + +While messy and harder to keep track of changes (since you can't see the diff directly), this has proven effective. You can make changes in your global `node_modules` directory on your machine in the `src` directory, then re-build the CLI using `npm run build` within the `cli` directory (where the package.json is). + +#### 3. Installing via git commit hash + +Prerequisites: +- babel-cli v6.8.0 installed globally on your machine +- commit should have `package.json` edited in such a way that the `prepare` script is replaced with a `preinstall` script + +You can see the changes you've made with your code and how they affect the CLI by using `npm i -g shoutem/cli#`, e.g.: +`npm i -g shoutem/cli#6874qbr` + +This can also be used for testing before release, unlike the other two methods. + +**NOTE:** Once a release is ready, make sure to turn the preinstall script back into a prepare script as users may not have babel-cli installed. diff --git a/package.json b/package.json index 93079d7..4a9d986 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,20 @@ { "name": "@shoutem/cli", - "version": "0.13.0", + "version": "0.13.1", "description": "Command-line tools for Shoutem applications", "repository": { "type": "git", "url": "https://github.com/shoutem/cli" }, "bin": { - "shoutem": "./src/shoutem.js" + "shoutem": "./build/shoutem.js" }, "scripts": { - "beta": "npm publish --access public --tag beta", + "build": "babel ./src --ignore ./src/templates --out-dir build --source-maps inline --copy-files", "extlint": "eslint", - "hotfix": "npm publish --access public --tag hotfix", - "lint": "eslint ./", - "prepublish": "dos2unix src/shoutem.js", - "shoutem": "node src/shoutem.js", + "lint": "eslint ./ --ignore-pattern build --ignore-pattern templates", + "prepare": "npm run build", + "shoutem": "node build/shoutem.js", "test": "mocha -R spec --require fetch-everywhere --compilers js:babel-core/register \"src/**/*spec.js\"" }, "author": "", diff --git a/src/cli.js b/src/cli.js index d5dc4b7..6552cdf 100644 --- a/src/cli.js +++ b/src/cli.js @@ -34,13 +34,13 @@ analytics.setArgv(process.argv); const cli = yargs.usage('Usage: shoutem [command] [-h]') .option('version', { alias: 'v', - description: 'Show version number' + description: 'Shows version number.' }) .commandDir('cli') .strict() .help() .epilog(`If you don't have a developer account, you can register at ${apiUrls.appBuilder.bold}.\n\n` + - `More detailed reference on how to use CLI can be found on the Developer Portal: ${cliReferenceUrl.bold}`) + `A more detailed reference on how to use CLI can be found on the Developer Portal: ${cliReferenceUrl.bold}.`) .alias('help', 'h'); const argv = cli.argv; diff --git a/src/cli/builder.js b/src/cli/builder.js index e8cb003..b884c83 100644 --- a/src/cli/builder.js +++ b/src/cli/builder.js @@ -3,7 +3,7 @@ import services from '../../config/services'; import {getPlatformConfig} from "../services/platform"; import {executeAndHandleError} from "../services/error-handler"; -export const description = 'Opens the app in the shoutem builder dashboard using default browser'; +export const description = 'Opens the app in the Shoutem Builder using the system default browser.'; export const command = 'builder [appId]'; export const builder = yargs => { return yargs diff --git a/src/cli/clone.js b/src/cli/clone.js index 8ea2131..bb7de52 100644 --- a/src/cli/clone.js +++ b/src/cli/clone.js @@ -1,7 +1,7 @@ import { executeAndHandleError } from '../services/error-handler'; import { clone } from '../commands/clone'; -export const description = 'Downloads a shoutem application with all it\'s extensions'; +export const description = 'Downloads a Shoutem app with all it\'s extensions.'; export const command = 'clone [appId]'; export const builder = yargs => { return yargs @@ -9,20 +9,20 @@ export const builder = yargs => { platform: { alias: 'p', - description: 'use external mobile app (ignores platform settings)', + description: 'Uses external mobile app (ignores platform settings).', requiresArg: true }, noconfigure: { - description: 'skip platform configuration step', + description: 'Skips platform configuration step.', type: 'boolean' }, dir: { - description: 'directory name for the cloned app', + description: 'Specifies directory name for the cloned app.', requiresArg: true }, force: { alias: 'f', - description: 'destroys destination directory if it already exists', + description: 'Destroys destination directory if it already exists.', type: 'boolean' } }) diff --git a/src/cli/configure.js b/src/cli/configure.js index e538b08..36a1493 100644 --- a/src/cli/configure.js +++ b/src/cli/configure.js @@ -1,20 +1,20 @@ import { executeAndHandleError } from '../services/error-handler'; import {configurePlatform, getPlatformConfig, getPlatformRootDir, setPlatformConfig} from '../services/platform'; -export const description = 'Runs platform\'s configure script to sync with native changes to local extensions'; +export const description = 'Runs the platform\'s configure script to install dependencies, link extensions and their dependencies and run extension build scripts.'; export const command = 'configure'; export const builder = yargs => { return yargs .options({ release: { alias: 'r', - description: '(re)configure the app with last published configuration from the shoutem server', + description: '(Re)configures the app with the latest (re)published configuration from the Shoutem builder.', type: 'boolean', default: false }, production: { alias: 'p', - description: 'configure the app for production mode build', + description: 'Configures the app for production build, used when publishing to the App Store or the Google Play store', type: 'boolean', default: false } diff --git a/src/cli/extension.js b/src/cli/extension.js index a100e3c..f3c58db 100644 --- a/src/cli/extension.js +++ b/src/cli/extension.js @@ -1,4 +1,4 @@ -export const description = 'Manage extensions within the current app'; +export const description = 'Manages extensions within the current app.'; export const command = 'extension '; export const builder = page => { return page diff --git a/src/cli/extension/add.js b/src/cli/extension/add.js index 1c71650..769cfa5 100644 --- a/src/cli/extension/add.js +++ b/src/cli/extension/add.js @@ -20,7 +20,7 @@ export const builder = yargs => { return yargs .options({ local: { - description: 'Extension is only added locally and is not published or installed on the shoutem server', + description: 'Extension is only added locally and is not published or installed on the Shoutem Builder', type: 'boolean', default: false } @@ -39,8 +39,8 @@ const postRunMessage = ${'shoutem theme add '.cyan} add a new theme - ${'shoutem page add'.cyan} - add a new settings page + ${'shoutem page add'.cyan} + add a new settings page `; export const handler = args => executeAndHandleError(() => addExtension(args)); @@ -66,8 +66,7 @@ export async function addExtension({ name, local, externalDestination }) { const cdCommand = 'cd ' + path.relative(process.cwd(), extensionPath); console.log('\nCongratulations, your new extension is ready!'.green.bold); - console.log(`You might try doing ${cdCommand.cyan} where you can:`); + console.log(`You can now do '${cdCommand.cyan}' where you can:`); console.log(postRunMessage); - console.log('Success!'.green.bold); - console.log('Happy coding!'); + console.log('Happy coding!\n'); } diff --git a/src/cli/extension/publish.js b/src/cli/extension/publish.js index 3ef8b48..d7af11d 100644 --- a/src/cli/extension/publish.js +++ b/src/cli/extension/publish.js @@ -9,7 +9,7 @@ import {updateExtension, getInstallation, installExtension} from "../../clients/ import confirmer from "../../services/confirmer"; import {getExtension} from "../../clients/extension-manager"; -export const description = 'Publish an extension from the app in the working directory'; +export const description = 'Publishes an extension from the app in the specified or current working directory.'; export const command = 'publish '; export const builder = yargs => { return yargs diff --git a/src/cli/init.js b/src/cli/init.js index ee44ecb..197625d 100644 --- a/src/cli/init.js +++ b/src/cli/init.js @@ -2,7 +2,7 @@ import {executeAndHandleError} from '../services/error-handler'; import {addExtension} from "./extension/add"; export const command = 'init '; -export const description = 'Create a scaffold of all files and folders required to build an extension.'; +export const description = 'Creates a basic extension structure, with all the required files and folders.'; export const builder = yargs => { return yargs.usage(`shoutem ${command}\n\n${description}`).strict(); }; diff --git a/src/cli/install.js b/src/cli/install.js index de9498e..58f3f1d 100644 --- a/src/cli/install.js +++ b/src/cli/install.js @@ -8,7 +8,7 @@ import msg from '../user_messages'; import { ensureUserIsLoggedIn } from '../commands/login'; import { handleError } from '../services/error-handler'; -export const description = 'Install the current extension to an application.'; +export const description = 'Install the current extension to an app on the Shoutem Builder.'; export const command = 'install'; export const builder = yargs => { @@ -16,12 +16,12 @@ export const builder = yargs => { .options({ app: { alias: 'a', - description: 'app id to install current extension to', + description: 'Specifies app id to install current extension to.', requiresArg: true }, new: { alias: 'n', - description: 'install to a new app with given name', + description: 'Creates new app with the given name and installs the extension to it.', type: 'string' }}) .usage(`usage: shoutem ${command} [options]\n\n${description}`); diff --git a/src/cli/last-error.js b/src/cli/last-error.js index 7140df1..f23340d 100644 --- a/src/cli/last-error.js +++ b/src/cli/last-error.js @@ -13,6 +13,6 @@ export async function handler() { })); console.log(`\nIf you think this error is caused by bug in the shoutem command, you can report the issue here: ${"https://github.com/shoutem/cli/issues".bold}`.yellow); } else { - console.log('No error'.green); + console.log('No error.'.green); } } diff --git a/src/cli/login.js b/src/cli/login.js index 113461d..9a5c755 100644 --- a/src/cli/login.js +++ b/src/cli/login.js @@ -1,7 +1,7 @@ import { loginUser } from '../commands/login'; import { executeAndHandleError } from '../services/error-handler'; -export const description = 'Log in and register as a Shoutem developer.\nProvide credentials in username:password format.'; +export const description = 'Handles Shoutem developer\'s authentication. Users already registered as Shoutem developers are simply logged in and non-developer users are first registered as developers and then logged in. Credentials can be provided in the username:password format as a command argument to skip the interactive menu.'; export const command = 'login [credentials]'; export function handler(args) { diff --git a/src/cli/logout.js b/src/cli/logout.js index d8fd604..56be99f 100644 --- a/src/cli/logout.js +++ b/src/cli/logout.js @@ -1,7 +1,7 @@ import logout from '../commands/logout'; import { executeAndHandleError } from '../services/error-handler'; -export const description = 'Erase all locally stored credentials.'; +export const description = 'Erases all locally stored credentials.'; export const command = 'logout'; export async function handler() { await executeAndHandleError(logout); diff --git a/src/cli/pack.js b/src/cli/pack.js index 8b2c0fd..f4c2c18 100644 --- a/src/cli/pack.js +++ b/src/cli/pack.js @@ -2,14 +2,14 @@ import shoutemPack from '../services/packer'; import { ensureInExtensionDir } from '../services/extension'; import { handleError } from '../services/error-handler'; -export const description = 'Pack shoutem extensions for upload'; +export const description = 'Packs a Shoutem extension for upload.'; export const command = 'pack'; export const builder = yargs => { return yargs .options({ nobuild: { type: 'boolean', - description: 'Pack the extension without building it.' + description: 'Packs the extension without building it.' } }) .usage(`shoutem ${command} [options]\n\n${description}`); diff --git a/src/cli/page.js b/src/cli/page.js index c14aa60..4f0005b 100644 --- a/src/cli/page.js +++ b/src/cli/page.js @@ -1,4 +1,4 @@ -export const description = 'Manage settings pages'; +export const description = 'Manages settings pages.'; export const command = 'page '; export const builder = page => { return page diff --git a/src/cli/page/add.js b/src/cli/page/add.js index ea3be6e..2dc81b4 100644 --- a/src/cli/page/add.js +++ b/src/cli/page/add.js @@ -4,7 +4,7 @@ import {askPageCreationQuestions} from "../../services/page"; import {instantiateExtensionTemplate} from "../../services/extension-template"; import {offerChanges} from "../../services/diff"; -export const description = 'Add a settings page to current extension'; +export const description = 'Adds a settings page to the current extension.'; export const command = 'add [name]'; export const handler = args => executeAndHandleError(async () => { diff --git a/src/cli/platform.js b/src/cli/platform.js index 3e78c81..ac229c8 100644 --- a/src/cli/platform.js +++ b/src/cli/platform.js @@ -1,4 +1,4 @@ -export const description = 'Manage platforms'; +export const description = 'Manages platforms.'; export const command = 'platform '; export const builder = page => page .commandDir('platform') diff --git a/src/cli/platform/create.js b/src/cli/platform/create.js index 80a44bc..8bb948f 100644 --- a/src/cli/platform/create.js +++ b/src/cli/platform/create.js @@ -11,7 +11,7 @@ import { uploadPlatformArchive } from '../../commands/platform'; import { createPlatformArchiveProvider } from '../../services/platform-archive'; import { platformMessages } from '../const'; -export const description = 'Create a new platform'; +export const description = 'Creates a new platform.'; export const command = 'create'; export const builder = yargs => yargs .options({ @@ -25,12 +25,12 @@ export const builder = yargs => yargs const postRunInstall = platformId => ` ${`shoutem platform install --app [app ID] --platform ${platformId}`.cyan} - To install this platform on an app + To install this platform to an app. `; const postRunPublish = platformId => ` ${`shoutem platform publish --platform ${platformId}`.cyan} - To publish this platform for everyone to use + To publish this platform to make it visible on the Builder. `; export const handler = args => executeAndHandleError(() => createPlatform(args)); @@ -56,12 +56,12 @@ export async function createPlatform({ url }) { const { appId } = await getPlatformConfig(); if (!_.isNil(appId)) { - if (await confirmer(`Do you want to install the new platform to this app (${appId})?`)) { + if (await confirmer(`Do you want to install the new platform to app ${appId}?`)) { await spinify(installPlatform({ app: appId, platform: platformResponse.id })); installed = true; } - console.log(`\nYou can manage your platforms for this app any time at https://builder.shoutem.com/app/${appId}/settings/platform`); + console.log(`\nYou can manage your platforms for this app any time at https://builder.shoutem.com/app/${appId}/settings/platform.`); } if (!published || !installed) { diff --git a/src/cli/platform/install.js b/src/cli/platform/install.js index 39995a9..b63f5a3 100644 --- a/src/cli/platform/install.js +++ b/src/cli/platform/install.js @@ -13,13 +13,13 @@ export const command = 'install'; export const builder = yargs => yargs .options({ app: { - description: 'Id of the application to install the new platform to', + description: 'Installs new platform into app with given app id.', type: 'number', requiresArg: true, alias: 'a', }, platform: { - description: 'Id of platform to install', + description: 'Installs platform with given id.', type: 'string', requiresArg: true, alias: 'p', diff --git a/src/cli/platform/list.js b/src/cli/platform/list.js index a20408f..75bf8a7 100644 --- a/src/cli/platform/list.js +++ b/src/cli/platform/list.js @@ -5,12 +5,12 @@ import { ensureUserIsLoggedIn } from '../../commands/login'; import { getAvailablePlatforms } from '../../commands/platform'; import { executeAndHandleError } from '../../services/error-handler'; -export const description = 'Lists available platforms'; +export const description = 'Lists available platforms.'; export const command = 'list'; export const builder = yargs => yargs .options({ all: { - description: 'Lists all available platforms', + description: 'Lists all available platforms.', type: 'boolean', alias: 'a', }, diff --git a/src/cli/platform/publish.js b/src/cli/platform/publish.js index e117139..6a2d8a0 100644 --- a/src/cli/platform/publish.js +++ b/src/cli/platform/publish.js @@ -7,12 +7,12 @@ import { getAvailablePlatforms } from '../../commands/platform'; import { publishPlatform } from '../../clients/extension-manager'; import { executeAndHandleError } from '../../services/error-handler'; -export const description = 'Publish a platform'; +export const description = 'Publishes a platform.'; export const command = 'publish'; export const builder = yargs => yargs .options({ platform: { - description: 'Id of platform to install', + description: 'Publishes platform with given id.', type: 'string', requiresArg: true, alias: 'p', diff --git a/src/cli/publish.js b/src/cli/publish.js index 63cb44d..2293cad 100644 --- a/src/cli/publish.js +++ b/src/cli/publish.js @@ -5,30 +5,28 @@ import { handleError } from '../services/error-handler'; import multiglob from '../services/multiglob'; import confirmPublish from '../commands/confirm-admin-action'; -export const description = 'Publish current extension version.'; +export const description = 'Publishes current extension version.'; export const command = 'publish [paths..]'; export const builder = yargs => { return yargs .options({ nobuild: { type: 'boolean', - description: 'Push and publish the extension without building it. Use this option carefully!' + description: 'Pushes and publishes the extension without building it. Use this option carefully!' }, nopush: { type: 'boolean', - description: 'Publish the extension without pushing it first. Use this option carefully!' + description: 'Publishes the extension without pushing it first. Use this option carefully!' } }) .usage(`shoutem ${command} [options]\n\n${description}`); }; export async function handler(args) { - if (!await confirmPublish('WARNING: you are about to publish using shoutem developer. Are you sure about that?')) { + if (!await confirmPublish('WARNING: You are about to publish using the \'shoutem\' developer account. Are you sure about that?')) { console.log('Publish aborted'.bold.yellow); return null; } - console.log('WARNING: shoutem publish command is deprecated. Use shoutem extension publish instead'.yellow.bold); - try { if (args.paths.length === 0) { await pushAndPublish(args); diff --git a/src/cli/push.js b/src/cli/push.js index 3a4342e..b532f44 100644 --- a/src/cli/push.js +++ b/src/cli/push.js @@ -12,31 +12,31 @@ export const builder = yargs => { .options({ nobuild: { type: 'boolean', - description: 'Push the extension without building it. Use this option carefully!' + description: 'Pushes the extension without building it. Use this option carefully!' }, noconfirm: { type: 'boolean', - description: 'Push extensions without asking for confirmation' + description: 'Pushes extensions without asking for confirmation.' }, without: { type: 'array', - description: 'Directory to skip. Can be passed multiple times for skipping multiple directories. Used only if multiple extensions are pushed.', + description: 'Specifies directory to skip. Can be passed multiple times for skipping multiple directories. Used only if multiple extensions are pushed.', requiresArg: true, }, nocheck: { type: 'boolean', - description: 'Push without checking for syntax errors' + description: 'Pushes without checking for syntax errors.' } }) .usage(`shoutem ${command} [options]\n\n${description}`); }; export const handler = args => executeAndHandleError(async () => { - if (!await confirmPush('WARNING: you are about tu push using shoutem developer. Are you sure about that?')) { + if (!await confirmPush('WARNING: You are about to push using the \'shoutem\' developer account. Are you sure about that?')) { console.log('Push aborted'.bold.yellow); return null; } - console.log('WARNING: shoutem push command is deprecated. Use shoutem publish instead'.yellow.bold); + if (!args.paths.length) { await uploadExtension(args); console.log(msg.push.complete()); @@ -46,4 +46,3 @@ export const handler = args => executeAndHandleError(async () => { args.paths = multiglob(args.paths); await pushAll(args); }); - diff --git a/src/cli/run.js b/src/cli/run.js index 3e1f9ba..5056f20 100644 --- a/src/cli/run.js +++ b/src/cli/run.js @@ -1,20 +1,20 @@ import forkTerminal from '@shoutem/fork-terminal'; import path from 'path'; -export const description = 'Run shoutem application on using Shoutem preview app'; +export const description = 'Runs and previews your local code with Shoutem preview app.'; export const command = 'run'; export const builder = yargs => { return yargs .options({ local: { alias: 'l', - description: 'don\'t use tunneling for Shoutem app, connect directly to packager. Note: ' + - 'this computer and iphone/android must be connected to the same network and port 8081 must be opened.', + description: 'Doesn\'t use tunneling for Shoutem app, connects directly to packager. Note: ' + + 'this computer and the mobile device must be connected to the same network and port 8081 must be opened.', type: 'boolean' }, small: { alias: 's', - description: 'display smaller ASCII QR code which could be unreadable in some fonts', + description: 'Displays smaller ASCII QR code which could be unreadable in some fonts.', type: 'boolean' } }) diff --git a/src/cli/schema.js b/src/cli/schema.js index 9f7cc95..0f28944 100644 --- a/src/cli/schema.js +++ b/src/cli/schema.js @@ -1,4 +1,4 @@ -export const description = 'Manage CMS schemas'; +export const description = 'Manages CMS schemas.'; export const command = 'schema '; export const builder = page => { return page diff --git a/src/cli/schema/add.js b/src/cli/schema/add.js index daeacd6..77f451b 100644 --- a/src/cli/schema/add.js +++ b/src/cli/schema/add.js @@ -6,7 +6,7 @@ import { handleError } from '../../services/error-handler'; const createSchemaAsync = Promise.promisify(createSchema); -export const description = 'Add schema to current extension'; +export const description = 'Adds schema to the current extension.'; export const command = 'add '; export async function handler(args) { try { diff --git a/src/cli/screen.js b/src/cli/screen.js index 6a7ca9d..4bbe7b7 100644 --- a/src/cli/screen.js +++ b/src/cli/screen.js @@ -1,4 +1,4 @@ -export const description = 'Manage extension screens'; +export const description = 'Manages extension screens.'; export const command = 'screen '; export const builder = screen => { return screen diff --git a/src/cli/screen/add.js b/src/cli/screen/add.js index a35193e..c3d2afd 100644 --- a/src/cli/screen/add.js +++ b/src/cli/screen/add.js @@ -4,7 +4,7 @@ import {askScreenCreationQuestions} from "../../services/screen"; import {instantiateExtensionTemplate} from "../../services/extension-template"; import {offerChanges} from "../../services/diff"; -export const description = 'Add a screen for applications running this extension'; +export const description = 'Adds a screen for apps running this extension.'; export const command = 'add [name]'; export const handler = args => executeAndHandleError(async () => { diff --git a/src/cli/shortcut.js b/src/cli/shortcut.js index 495fd95..fa11593 100644 --- a/src/cli/shortcut.js +++ b/src/cli/shortcut.js @@ -1,4 +1,4 @@ -export const description = 'Manage application shortcuts'; +export const description = 'Manages extension shortcuts.'; export const command = 'shortcut '; export const builder = shortcut => { return shortcut diff --git a/src/cli/shortcut/add.js b/src/cli/shortcut/add.js index a31ad87..b16cd7f 100644 --- a/src/cli/shortcut/add.js +++ b/src/cli/shortcut/add.js @@ -4,7 +4,7 @@ import {ensureInExtensionDir, loadExtensionJson} from "../../services/extension" import {instantiateExtensionTemplate} from "../../services/extension-template"; import {offerChanges} from "../../services/diff"; -export const description = 'Add an application shortcut'; +export const description = 'Adds a new app shortcut to the extension.'; export const command = 'add [name]'; export const handler = args => executeAndHandleError(async () => { const extJson = await loadExtensionJson(); diff --git a/src/cli/show.js b/src/cli/show.js index d2b7839..f69b38b 100644 --- a/src/cli/show.js +++ b/src/cli/show.js @@ -2,7 +2,7 @@ import show from '../commands/show.js'; import { executeAndHandleError } from '../services/error-handler'; export const command = 'show'; -export const description = 'Shows user status and list of linked extensions'; +export const description = 'Shows user status and list of linked extensions.'; export const handler = args => executeAndHandleError(() => show(args)); export function builder(yargs) { return yargs diff --git a/src/cli/theme.js b/src/cli/theme.js index 7cd3a9d..ff6bc21 100644 --- a/src/cli/theme.js +++ b/src/cli/theme.js @@ -1,4 +1,4 @@ -export const description = 'Manage application themes'; +export const description = 'Manages extension themes.'; export const command = 'theme '; export const builder = theme => { return theme diff --git a/src/cli/theme/add.js b/src/cli/theme/add.js index c72dda7..fee5717 100644 --- a/src/cli/theme/add.js +++ b/src/cli/theme/add.js @@ -2,7 +2,7 @@ import { createTheme } from '../../commands/theme'; import { handleError } from '../../services/error-handler'; import { ensureVariableName } from '../../services/cli-parsing'; -export const description = 'Add a theme to the current extension'; +export const description = 'Adds a theme to the current extension.'; export const command = 'add '; export async function handler(args) { try { diff --git a/src/cli/uninstall.js b/src/cli/uninstall.js index 4eeb5e9..a8ffd52 100644 --- a/src/cli/uninstall.js +++ b/src/cli/uninstall.js @@ -4,14 +4,14 @@ import { getExtensionId } from '../clients/extension-manager'; import msg from '../user_messages'; import { handleError } from '../services/error-handler'; -export const description = `Uninstall current extension from an app.`; +export const description = 'Uninstalls the current extension from an app.'; export const command = 'uninstall'; export const builder = yargs => { return yargs .options({ app: { alias: 'a', - description: 'uninstall local extension from an app', + description: 'Uninstalls local extension from an app.', requiresArg: true, demand: true } diff --git a/src/cli/use.js b/src/cli/use.js index 6944997..917debe 100644 --- a/src/cli/use.js +++ b/src/cli/use.js @@ -7,7 +7,7 @@ export const command = 'use '; const production = { command: 'production', - description: 'Switch to shoutem live env', + description: 'Switches to the Shoutem production environment.', async handler() { await setHostEnvName('production'); console.log(msg.use.complete('production', await getValue('developer'))); @@ -16,7 +16,7 @@ const production = { const dev = { command: 'dev', - description: 'Switch to sauros dev env', + description: 'Switches to the Shoutem dev environment.', async handler() { await setHostEnvName('dev'); console.log(msg.use.complete('dev', await getValue('developer'))); @@ -25,7 +25,7 @@ const dev = { const local = { command: 'local', - description: 'Use api endpoints set in OS env variables', + description: 'Switches to the local environment, using endpoints set in OS environment variables.', async handler() { await setHostEnvName('local'); console.log(msg.use.complete('local', await getValue('developer'))); @@ -34,7 +34,7 @@ const local = { const qa = { command: 'qa', - description: 'Switch to using sauros qa env', + description: 'Switches to the Shoutem QA environment.', async handler() { await setHostEnvName('qa'); console.log(msg.use.complete('qa', await getValue('developer'))); diff --git a/src/cli/whoami.js b/src/cli/whoami.js index 6d8b735..564c595 100644 --- a/src/cli/whoami.js +++ b/src/cli/whoami.js @@ -2,7 +2,7 @@ import msg from '../user_messages'; import { getValue } from '../services/cache-env'; export const command = 'whoami'; -export const description = 'Username of the current user.'; +export const description = 'Displays the current user\'s username.'; export async function handler() { try { const dev = await getValue('developer'); diff --git a/src/clients/auth-service.js b/src/clients/auth-service.js index 639d7db..f208722 100644 --- a/src/clients/auth-service.js +++ b/src/clients/auth-service.js @@ -22,7 +22,7 @@ export class UnauthorizedError { Used when bad username or password is supplied. */ constructor(url, response, statusCode) { - this.message = 'Username or password is not valid'; + this.message = 'Username or password is not valid.'; this.url = url; this.response = response; this.statusCode = statusCode; @@ -30,7 +30,7 @@ export class UnauthorizedError { } const tokensUrl = new URI(services.authService).segment('/v1/auth/tokens').toString(); -const appAccessTokenUrl = new URI(services.legacyService).segment('/v1/auth/tokens').toString(); +const appAccessTokenUrl = new URI(services.authService).segment('/v1/auth/tokens').toString(); function getBasicAuthHeaderValue(email, password) { return 'Basic ' + new Buffer(`${email}:${password}`).toString('base64'); diff --git a/src/commands/clone.js b/src/commands/clone.js index a90e5d1..a2e90e3 100644 --- a/src/commands/clone.js +++ b/src/commands/clone.js @@ -30,7 +30,7 @@ export async function pullExtensions(appId, destinationDir) { let i = 0; for(const inst of installations) { i++; - await spinify(pullExtension(destinationDir, inst), `Downloading extension ${i}/${n}: ${inst.canonicalName}`); + await spinify(pullExtension(destinationDir, inst), `Downloading extension ${i}/${n}: ${inst.canonicalName}...`); } } @@ -41,7 +41,7 @@ async function pullExtension(destinationDir, { extension, canonicalName }) { await downloadFile(url, { directory: tgzDir, filename: 'extension.tgz' }); await shoutemUnpack(path.join(tgzDir, 'extension.tgz'), path.join(destinationDir, canonicalName)); } catch (err) { - err.message = `Could not fetch extension ${canonicalName}`; + err.message = `Could not fetch extension ${canonicalName}.`; throw err; } } @@ -72,7 +72,7 @@ async function queryPathExistsAction(destinationDir, oldDirectoryName) { const { action } = await inquirer.prompt({ type: 'list', name: 'action', - message: `Directory ${oldDirectoryName} already exists`, + message: `Directory ${oldDirectoryName} already exists.`, choices: [{ name: 'Overwrite', value: 'overwrite' @@ -97,7 +97,7 @@ async function queryPathExistsAction(destinationDir, oldDirectoryName) { message: 'New directory name', async validate(dirName) { if (dirName.indexOf(' ') > -1) { - return 'No spaces are allowed'; + return 'No spaces are allowed.'; } if (await pathExists(path.join(destinationDir, dirName))) { return `Directory ${dirName} already exists.` @@ -128,13 +128,13 @@ export async function clone(opts, destinationDir) { let appDir = path.join(destinationDir, directoryName); if (opts.force) { - await spinify(rmrf(appDir), `Destroying directory ${directoryName}`); + await spinify(rmrf(appDir), `Destroying directory ${directoryName}...`); } if (await pathExists(appDir)) { const action = await queryPathExistsAction(destinationDir, directoryName); if (action.type === 'overwrite') { - await spinify(rmrf(appDir), `Destroying directory ${directoryName}`); + await spinify(rmrf(appDir), `Destroying directory ${directoryName}...`); } else if (action.type === 'abort') { console.log('Clone aborted.'.bold.yellow); return; @@ -153,17 +153,17 @@ export async function clone(opts, destinationDir) { console.log(`Cloning \`${name}\` to \`${directoryName}\`...`); if (opts.platform) { - await spinify(copy(opts.platform, appDir), 'Copying platform code'); + await spinify(copy(opts.platform, appDir), 'Copying platform code...'); } else { const platform = await appManager.getApplicationPlatform(opts.appId); ensurePlatformCompatibility(platform); await downloadApp(opts.appId, appDir, { - progress: createProgressHandler({ msg: 'Downloading shoutem platform' }), + progress: createProgressHandler({ msg: 'Downloading shoutem platform.' }), useCache: !opts.force, versionCheck: mobileAppVersion => { if (!semver.gte(mobileAppVersion, '0.58.9')) { - throw new Error('This version of CLI only supports platforms containing mobile app 0.58.9 or higher'); + throw new Error('This version of CLI only supports platforms containing mobile app 0.58.9 or higher.'); } } }); diff --git a/src/commands/init.js b/src/commands/init.js index 8e1d086..a82df1b 100644 --- a/src/commands/init.js +++ b/src/commands/init.js @@ -3,6 +3,7 @@ import inquirer from 'inquirer'; import decamelize from 'decamelize'; import { pathExists } from 'fs-extra'; import path from 'path'; +import semver from 'semver'; import { ensureUserIsLoggedIn } from '../commands/login'; import msg from '../user_messages'; import { getPlatforms } from '../clients/extension-manager'; @@ -30,9 +31,7 @@ export async function promptExtensionInit(extName) { name: 'version', message: 'Version', default: version, - validate: value => value.match(/^(\d+)\.(\d+)\.(\d+)+$/) - ? true - : 'Version must contain numbers in format X.Y.Z', + validate: value => semver.valid(value) ? true : 'The version must be a valid semver version value.', }, { name: 'description', message: 'Description', diff --git a/src/commands/login.js b/src/commands/login.js index e12c904..27396d0 100644 --- a/src/commands/login.js +++ b/src/commands/login.js @@ -43,7 +43,7 @@ function promptUserCredentials(args = {}) { function promptDeveloperName() { /* eslint no-confusing-arrow: 0 */ - console.log('Enter developer name.'); + console.log('Create a developer name. It should only contain lower-case letters and dashes, e.g.: my-dev-name.'); return inquirer.prompt({ name: 'devName', message: 'Developer name', @@ -104,7 +104,7 @@ export async function ensureUserIsLoggedIn(shouldThrow = false) { } if (shouldThrow) { - throw new Error('Not logged in, use `shoutem login` command to login'); + throw new Error('Not logged in, use `shoutem login` command to login.'); } else { return await loginUser(); } diff --git a/src/commands/platform.js b/src/commands/platform.js index ba0564c..e8f1d65 100644 --- a/src/commands/platform.js +++ b/src/commands/platform.js @@ -13,12 +13,12 @@ export async function uploadPlatformArchive(platformArchiveProvider) { await platformArchiveProvider.validateShoutemIgnore(); } - const archivePath = await spinify(platformArchiveProvider.getArchivePath(), 'Packing the platform'); + const archivePath = await spinify(platformArchiveProvider.getArchivePath(), 'Packing the platform...'); if (!fs.pathExists(archivePath)) { - throw new Error('Unable to create or download archive'); + throw new Error('Unable to create or download archive.'); } - await spinify(validatePlatformArchive(platformArchiveProvider), 'Validating platform archive'); + await spinify(validatePlatformArchive(platformArchiveProvider), 'Validating platform archive...'); const { size } = await fs.stat(archivePath); const stream = fs.createReadStream(archivePath); @@ -35,9 +35,9 @@ export async function uploadPlatformArchive(platformArchiveProvider) { ); if (spinner) { spinner.stop(true); - console.log(`Processing upload... [${'OK'.green.bold}]`); + console.log(`Processing upload... [${'OK'.green.bold}].`); } - console.log(`${msg.platform.uploadingInfo(getHostEnvName())} [${'OK'.green.bold}]`); + console.log(`${msg.platform.uploadingInfo(getHostEnvName())} [${'OK'.green.bold}].`); platformArchiveProvider.cleanUp(); diff --git a/src/commands/push-all.js b/src/commands/push-all.js index 18741d8..f3fa953 100644 --- a/src/commands/push-all.js +++ b/src/commands/push-all.js @@ -22,7 +22,7 @@ export async function pushAll(args) { let { pathsToPush } = args.noconfirm || await prompt({ type: 'checkbox', name: 'pathsToPush', - message: `Check extensions you want to push to ${getHostEnvName()}?`, + message: `Check which extensions you want to push to ${getHostEnvName()}.`, choices: extPaths.concat(new Separator()), default: extPaths, pageSize: 20 diff --git a/src/commands/push.js b/src/commands/push.js index c38d5b6..752002a 100644 --- a/src/commands/push.js +++ b/src/commands/push.js @@ -26,7 +26,7 @@ export async function uploadExtension(opts = {}, extensionDir = ensureInExtensio await extLint(extensionDir); console.log(`[${'OK'.green.bold}]`); } catch (err) { - err.message = 'Syntax errors detected, aborting push! Use `shoutem push --nocheck` to override'; + err.message = 'Syntax errors detected, aborting push! Use `shoutem push --nocheck` to override, but use with caution!'; throw err; } } @@ -71,7 +71,7 @@ export async function promptPublishableVersion(extJson) { while (true) { const { name, version } = extJson; const canonical = getExtensionCanonicalName(dev.name, name, version); - const canExtensionBePublished = await spinify(canPublish(canonical), `Checking if version ${version} can be published`); + const canExtensionBePublished = await spinify(canPublish(canonical), `Checking if version ${version} can be published...`); if (canExtensionBePublished) { return; } diff --git a/src/commands/run.js b/src/commands/run.js index 735a539..d83de2b 100644 --- a/src/commands/run.js +++ b/src/commands/run.js @@ -17,11 +17,11 @@ export default async function (options) { const { packagerProcess } = await startPackager(await getPlatformRootDir()); if (options.local) { - console.log('Make sure that the phone running Shoutem app is connected to the same network as this computer'.yellow); + console.log('Make sure that the device running the Shoutem app is connected to the same network as this computer.'.yellow); if (process.platform === 'win32') { - console.log('If Shoutem app on your phone fails to load, try opening the 8081 TCP port manually from your Windows Firewall or disabling the firewall temporarily'.yellow); + console.log('If the Shoutem app on your phone fails to load, try opening the 8081 TCP port manually from your Windows Firewall or disabling the firewall temporarily.'.yellow); } else { - console.log('Make sure that the 8081 TCP port is not blocked on this computer'.yellow); + console.log('Make sure that the 8081 TCP port is not blocked on this computer.'.yellow); } await printMobilizerQR(ip.address(), 8081, options); } else { @@ -32,7 +32,7 @@ export default async function (options) { await packagerProcess; } catch (err) { if (!/^win/.test(process.platform) && !await commandExists('watchman')) { - console.log('HINT: You should probably install Facebook\'s `watchman` before running `shoutem run` command'.bold.yellow); + console.log('HINT: You should probably install Facebook\'s `watchman` before running `shoutem run` command.'.bold.yellow); } await tunnel.stop(); await handleError(err); diff --git a/src/commands/show.js b/src/commands/show.js index e506316..49e1e69 100644 --- a/src/commands/show.js +++ b/src/commands/show.js @@ -17,5 +17,5 @@ export default async function(args) { console.log(msg.login.complete(developer)); } - console.log(`Home directory: \`${getHomeDir()}\` (customizable through SHOUTEM_CLI_HOME env variable, may require restart of terminal)`); + console.log(`Home directory: \`${getHomeDir()}\` (customizable through SHOUTEM_CLI_HOME env variable, may require restart of terminal).`); } diff --git a/src/commands/update-cli.js b/src/commands/update-cli.js index 135d70e..9a4bd35 100644 --- a/src/commands/update-cli.js +++ b/src/commands/update-cli.js @@ -1,6 +1,6 @@ import { isLatest } from '../services/npmjs'; import apiUrls from '../../config/services'; -import msg from '../../src/user_messages'; +import msg from '../user_messages'; import { spawn } from 'child-process-promise'; import { version } from '../../package.json'; import confirm from '../services/confirmer'; @@ -27,7 +27,7 @@ export default async function () { const updateConfirmed = await confirmUpdate(); if (!updateConfirmed) { - console.log('Warning: This is an outdated version of shoutem CLI'.bold.yellow); + console.log('Warning: This is an outdated version of the Shoutem CLI.'.bold.yellow); console.log('Install the new one with: `npm install -g @shoutem/cli`. You might need to run it with `sudo` prefix.'.yellow); return false; } @@ -43,7 +43,7 @@ export default async function () { } } - console.log('Update complete'); + console.log('Update complete.'); await spawn('shoutem', process.argv.filter((_, index) => index > 1), { stdio: 'inherit' }); return true; diff --git a/src/scripts/shoutem-run.js b/src/scripts/shoutem-run.js index 6152356..4bc5104 100644 --- a/src/scripts/shoutem-run.js +++ b/src/scripts/shoutem-run.js @@ -8,7 +8,7 @@ const rl = readline.createInterface({ }); function waitForEnter() { - console.log('\nPress ENTER to end this process'); + console.log('\nPress ENTER to end this process.'); rl.on('line', () => { rl.close(); }); diff --git a/src/services/app-selector.js b/src/services/app-selector.js index a04b214..fbe3399 100644 --- a/src/services/app-selector.js +++ b/src/services/app-selector.js @@ -5,7 +5,7 @@ import * as logger from './logger'; import * as cache from './cache-env'; export default async function(apps = null) { - apps = apps || await spinify(getLatestApps(), 'Fetching applications'); + apps = apps || await spinify(getLatestApps(), 'Fetching applications...'); logger.info('appSelector', apps); return (await prompt({ diff --git a/src/services/error-handler.js b/src/services/error-handler.js index 83f7e30..86aebfb 100644 --- a/src/services/error-handler.js +++ b/src/services/error-handler.js @@ -26,7 +26,7 @@ export function getErrorMessage(err) { } if (err.statusCode === 401 || err.statusCode === 403) { - return 'Access denied, use `shoutem login` command to login'; + return 'Access denied, use `shoutem login` command to login.'; } if (_.get(err, 'body.errors')) { @@ -44,7 +44,7 @@ export function getErrorMessage(err) { } - return 'Unrecognized error. Run `shoutem last-error` for more additional details' + return 'Unrecognized error. Run `shoutem last-error` for additional details.' } let reportInfoPrinted = false; diff --git a/src/services/extension.js b/src/services/extension.js index 21f34e4..92c028a 100644 --- a/src/services/extension.js +++ b/src/services/extension.js @@ -4,7 +4,7 @@ import * as analytics from './analytics'; import {readJsonFile, writeJsonFile} from "./data"; export function getExtensionCanonicalName(devName, extName, extVersion) { - const canonicalName = `${devName}.${extName}-${extVersion}`; + const canonicalName = `${devName}.${extName}@${extVersion}`; analytics.setExtensionCanonicalName(canonicalName); diff --git a/src/services/platform-archive.js b/src/services/platform-archive.js index 45e9231..12b2b82 100644 --- a/src/services/platform-archive.js +++ b/src/services/platform-archive.js @@ -16,7 +16,6 @@ const SHOUTEM_IGNORE_FILE_NAME = '.shoutemignore'; const ARCHIVE_FORMAT = 'zip'; const DEFAULT_SHOUTEM_IGNORE = ` -# we don't neet it .git # node modules will get installed during the build process of the app node_modules diff --git a/src/services/platform-selector.js b/src/services/platform-selector.js index fabac9f..dc9153a 100644 --- a/src/services/platform-selector.js +++ b/src/services/platform-selector.js @@ -5,13 +5,13 @@ import { spinify } from './spinner'; import { getAvailablePlatforms } from '../commands/platform'; export default async function (platforms = null) { - platforms = platforms || await spinify(getAvailablePlatforms(), 'Fetching platforms'); + platforms = platforms || await spinify(getAvailablePlatforms(), 'Fetching platforms...'); logger.info('platformSelector', platforms); return (await prompt({ type: 'list', name: 'platformId', - message: 'Select your platform', + message: 'Select your platform.', choices: platforms.map(platform => ({ name: `${_.get(platform, ['author', 'name'])}@${platform.version} (${platform.id})`, value: platform.id, diff --git a/src/services/platform.js b/src/services/platform.js index 314b681..40d3251 100644 --- a/src/services/platform.js +++ b/src/services/platform.js @@ -8,7 +8,6 @@ import decompressUri from './decompress'; import cliUrls from '../../config/services'; import { writeJsonFile} from './data'; import * as npm from './npm'; -import { ensureYarnInstalled } from './yarn'; import * as reactNative from './react-native'; import * as analytics from './analytics'; import { pathExists, readJson, readFile, writeFile } from 'fs-extra'; @@ -75,7 +74,6 @@ export async function setPlatformConfig(platformDir, mobileConfig) { } export async function configurePlatform(platformDir) { - await ensureYarnInstalled(); await reactNative.ensureInstalled(); if (process.platform === 'darwin' && !await commandExists('pod')) { throw new Error('Missing `pods` command. Please install cocoapods and run `shoutem configure` in the ' + diff --git a/src/services/screen.js b/src/services/screen.js index 60963be..5c363ae 100644 --- a/src/services/screen.js +++ b/src/services/screen.js @@ -27,7 +27,7 @@ export async function askScreenCreationQuestions(opts) { const screen = await prompt(createScreenCreationQuestions(opts)); const parentName = screen.name; - const message = "Shortcut is required for a screen to appear in the app. Create one now?"; + const message = "A shortcut is required for a screen to appear in the app. Create one now?"; const { shouldCreateShortcut, ...shortcut } = await askShortcutCreationQuestions({ ...opts, parentName, message }); if (shouldCreateShortcut) { screen.newShortcut = shortcut; diff --git a/src/services/shortcut.js b/src/services/shortcut.js index a996b6b..d0649d0 100644 --- a/src/services/shortcut.js +++ b/src/services/shortcut.js @@ -21,7 +21,7 @@ export function addShortcut(extJson, { name, title, description, screenName, pag function validateShortcutName(name, existingShortcuts) { if (!isVariableName(name)) { - return 'Shortcut\'s name must be a valid js variable name'; + return 'A shortcut name must be a valid JavaScript variable name.'; } if (_.find(existingShortcuts, { name })) { return `${name} already exists`; diff --git a/src/services/template.js b/src/services/template.js index 2de7ace..2c46bbb 100644 --- a/src/services/template.js +++ b/src/services/template.js @@ -5,7 +5,7 @@ import path from 'path'; import Mustache from 'mustache'; import { pathExists } from 'fs-extra'; -const templatesDirectory = path.join(__dirname, '..', 'templates'); +const templatesDirectory = path.join(__dirname, '../..', 'src/templates'); export function load(pathWithSlashes, templateContext) { const p = path.join(templatesDirectory, ...pathWithSlashes.split('/')); diff --git a/src/services/yarn.js b/src/services/yarn.js deleted file mode 100644 index b35ed65..0000000 --- a/src/services/yarn.js +++ /dev/null @@ -1,25 +0,0 @@ -import { spawn } from 'child-process-promise'; -import msg from '../user_messages'; -import commandExists from './command-exists'; - -export async function ensureYarnInstalled() { - if (!await commandExists('yarn')) { - throw new Error(msg.yarn.missing()); - } -} - -export async function install(cwd = process.cwd()) { - await ensureYarnInstalled(); - await spawn('yarn', ['install'], { cwd, stdio: 'inherit' }); -} - -export async function run(cwd, task, taskArgs = null, stdio = 'inherit') { - await ensureYarnInstalled(); - const opts = {cwd, stdio }; - - if (taskArgs) { - return await spawn('yarn', ['run', task, '--', ...taskArgs], opts); - } else { - return await spawn('yarn', ['run', task], opts); - } -} diff --git a/src/shoutem.js b/src/shoutem.js index fde798a..7803cb7 100755 --- a/src/shoutem.js +++ b/src/shoutem.js @@ -1,22 +1,29 @@ #!/usr/bin/env node -const semver = require('semver'); +require('colors'); const path = require('path'); -const getHomeDir = require('./home-dir'); +const semver = require('semver'); const packageJson = require('../package.json'); -require('colors'); +const getHomeDir = require('./home-dir'); const homeDir = getHomeDir(); +const nodeVer = process.versions.node; +const cliArgs = process.argv.slice(2); + +if (cliArgs[0] === '-v' || cliArgs[0] === '--version') { + console.log(packageJson.version); + process.exit(0); +} if (!path.isAbsolute(homeDir)) { console.log(`ERROR: path ${homeDir} is not an absolute path.`.red); - console.log('Please set your SHOUTEM_CLI_HOME environmental variable to an absolute path'.red); + console.log('Please set your SHOUTEM_CLI_HOME environmental variable to an absolute path.'.red); process.exit(1); } -if (semver.lt(process.versions.node, '6.0.0')) { - console.error(`You appear to be using Node v${process.versions.node}, however, Node 6 or later is required`); - return; +if (semver.lt(nodeVer, '6.0.0')) { + console.error(`You appear to be using Node v${nodeVer}, however, Node 6 or later is required.`); + process.exit(1); } const babelCachePath = path.join(homeDir, 'cache', 'babel-cache'); diff --git a/src/user_messages.js b/src/user_messages.js index 1f7945f..6c90852 100644 --- a/src/user_messages.js +++ b/src/user_messages.js @@ -11,7 +11,7 @@ export default { missingEnv: () => 'Mobile environment does not exist, try `shoutem env install` first', alreadyLatest: version => `Already at latest version ${version}. Use \`shoutem env install -f\` to reinstall.`, complete: pkgJson => `Mobile environment updated to version ${pkgJson.version}. ` + - 'You can now run `shoutem run-ios` or `shoutem run-android`' + 'You can now run `shoutem run-ios` or `shoutem run-android`.' }, info: { downloading: version => `Downloading environment v${version}...`, @@ -30,18 +30,18 @@ export default { 'Please, clear the folder and run the initialization process again.' }, install: { - complete: () => 'Extension installed', + complete: () => 'Extension installed.', completeOntoNew: app => `Extension installed onto newly created \`${app}\` application.`, - seeNewInBrowser: url => `See it in browser: ${url}`, - notExtensionDir: () => 'No extension found. Try `shoutem push` before installing.' + seeNewInBrowser: url => `See it in a browser: ${url}.`, + notExtensionDir: () => 'No extension found. Try using `shoutem push` before installing.' }, uninstall: { - missingExtension: () => 'Extension does not exist. You must `shoutem push` it first.', + missingExtension: () => 'The extension does not exist. It should be pushed using `shoutem push` first.', missingInstallation: () => 'Extension not installed.', complete: () => 'Extension uninstalled.' }, link: { - alreadyLinked: () => 'Directory already linked', + alreadyLinked: () => 'Directory already linked.', complete: () => 'Directory successfully linked. Please, kill the packager before running the app.' }, login: { @@ -102,32 +102,28 @@ export default { use: { complete: (serverEnv, developer) => `Using server \`${serverEnv}\`` + (developer ? ` as user ${developer.name}.` : '.'), invalidEnv: serverEnv => `${serverEnv} is not a valid option\nRun shoutem use -h for possible options.`, - show: serverEnv => `Using server \`${serverEnv}\``, + show: serverEnv => `Using server \`${serverEnv}\`.`, }, run: { missingId: () => 'Shoutem app id is required for the first run.', - info: (platform, config) => `Running ${platform} shoutem app with id ${config.appId}`, + info: (platform, config) => `Running ${platform} Shoutem app with id ${config.appId}.`, complete: platform => `Finished running ${platform} app.`, - missingConfig: () => 'Mobile environment wasn\'t correctly installed. Please run `shoutem env install -f` to reinstall', - killPackagerAndAdb: () => 'Could not clean up the build directory. Please check that react-packager and adb are not running' + missingConfig: () => 'Mobile environment wasn\'t correctly installed. Please run `shoutem env install -f` to reinstall.', + killPackagerAndAdb: () => 'Could not clean up the build directory. Please check that react-packager and adb are not running.' }, show: { missingEnv: () => 'No shoutem env was set. Please run shoutem env install.', - version: packageJson => `Mobile environment version: ${packageJson.version}`, - app: config => `Currently used shoutem app id: ${config.appId}`, - missingApp: () => 'No shoutem app is currently used.', - missingExtensions: () => 'No local extension is currently linked', + version: packageJson => `Mobile environment version: ${packageJson.version}.`, + app: config => `Currently used Shoutem app id: ${config.appId}.`, + missingApp: () => 'No Shoutem app is currently used.', + missingExtensions: () => 'No local extension is currently linked.', listExtensions: paths => 'Linked directories:\n' + paths.map(path => ` ${path}`).join('\n'), }, pack: { - missingBuildTask: dir => `Skipping build for \`${dir}\` due to missing build task` - }, - yarn: { - missing: () => 'Missing yarn command. Please install yarn by running `npm install -g yarn`.', - outdated: (minVersion) => `Yarn version outdated. Please update yarn to v${minVersion} or newer by running \`npm install -g yarn\`` + missingBuildTask: dir => `Skipping build for \`${dir}\` due to missing build task.` }, reactNative: { - killPackager: () => 'Use `shoutem run-ios --ignore-packager` or kill the packager process before running the app', + killPackager: () => 'Use `shoutem run-ios --ignore-packager` or kill the packager process before running the app.', missing: () => 'Missing react-native command. Please install react-native by running \`npm install -g react-native-cli\`.' }, cocoapods: { @@ -135,12 +131,12 @@ export default { }, ios: { notOnMac: () => 'Unfortunately, Apple only lets you develop for iOS on a Mac. However, ' + - 'you can develop an application, test it on Android and see how it works on iPhone in Shoutem Builder!' + 'you can develop an application, test it on Android and see how it works on iPhone in the Shoutem Builder!' }, node: { - outdated: minVersion => `Your node version is too old. Please update node to version ${minVersion} or newer` + outdated: minVersion => `Your node version is too old. Please update node to version ${minVersion} or newer.` }, version: { - updateRequired: () => 'WARNING: This is an outdated version of shoutem CLI. Do you want to update it?' + updateRequired: () => 'WARNING: This is an outdated version of the Shoutem CLI. Do you want to update it?' } }