diff --git a/package.json b/package.json index 0571bea4..14dc17be 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "node": ">= 8" }, "dependencies": { + "chalk": "^2.4.2", "cheerio": "^1.0.0-rc.1", "commander": "^2.8.1", "denodeify": "^1.2.1", @@ -52,6 +53,7 @@ "yazl": "^2.2.2" }, "devDependencies": { + "@types/chalk": "^2.2.0", "@types/cheerio": "^0.22.1", "@types/markdown-it": "0.0.2", "@types/node": "^8", diff --git a/src/main.ts b/src/main.ts index 3c004663..d3eca7ba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,7 +5,7 @@ import { show } from './show'; import { search } from './search'; import { listPublishers, createPublisher, deletePublisher, loginPublisher, logoutPublisher } from './store'; import { getLatestVersion } from './npm'; -import { CancellationToken, isCancelledError } from './util'; +import { CancellationToken, isCancelledError, ERROR } from './util'; import * as semver from 'semver'; import { isatty } from 'tty'; const pkg = require('../package.json'); @@ -19,7 +19,7 @@ function fatal(message: any, ...args: any[]): void { } } - console.error('Error:', message, ...args); + console.error(`${ERROR} `, message, ...args); if (/Unauthorized\(401\)/.test(message)) { console.error(`Be sure to use a Personal Access Token which has access to **all accessible accounts**. diff --git a/src/npm.ts b/src/npm.ts index 3dea8c72..f5467a29 100644 --- a/src/npm.ts +++ b/src/npm.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as cp from 'child_process'; import * as parseSemver from 'parse-semver'; import * as _ from 'lodash'; -import { CancellationToken } from './util'; +import { CancellationToken, ERROR } from './util'; interface IOptions { cwd?: string; @@ -84,7 +84,7 @@ function asYarnDependency(prefix: string, tree: YarnTreeNode, prune: boolean): Y name = parseResult.name; version = parseResult.version; } catch (err) { - console.error('Failed to parse dependency:', tree.name); + console.error(`${ERROR} Failed to parse dependency:`, tree.name); return null; } diff --git a/src/package.ts b/src/package.ts index 638a792a..a22977fc 100644 --- a/src/package.ts +++ b/src/package.ts @@ -234,7 +234,7 @@ class ManifestProcessor extends BaseProcessor { } if (!this.manifest.repository) { - console.warn(`A 'repository' field is missing from the 'package.json' manifest file.`); + console.warn(`${util.WARN} A 'repository' field is missing from the 'package.json' manifest file.`); if (!/^y$/i.test(await util.read('Do you want to continue? [y/N] '))) { throw new Error('Aborted'); @@ -854,7 +854,7 @@ export async function packageCommand(options: IPackageOptions = {}): Promise Promise.reject(err.statusCode === 409 ? `${fullName} already exists.` : err)) - .then(() => console.log(`Successfully published ${fullName}!\nYour extension will live at ${getPublishedUrl(name)} (might take a few seconds for it to show up).`)); + .then(() => console.log(`${DONE} Published ${fullName}\nYour extension will live at ${getPublishedUrl(name)} (might take a few seconds for it to show up).`)); }) .catch(err => { const message = err && err.message || ''; @@ -207,6 +207,6 @@ export function unpublish(options: IUnpublishOptions = {}): Promise { .then(() => pat) .then(getGalleryAPI) .then(api => api.deleteExtension(publisher, name)) - .then(() => console.log(`Successfully deleted ${fullName}!`)); + .then(() => console.log(`${DONE} Deleted extension: ${fullName}!`)); }); } diff --git a/src/show.ts b/src/show.ts index e5f91a0c..9a793bc5 100644 --- a/src/show.ts +++ b/src/show.ts @@ -1,4 +1,4 @@ -import { getPublicGalleryAPI } from './util'; +import { getPublicGalleryAPI, ERROR } from './util'; import { ExtensionQueryFlags, PublishedExtension } from 'vso-node-api/interfaces/GalleryInterfaces'; import { ViewTable, formatDate, formatDateTime, ratingStars, tableView, indentRow, wordWrap, icons } from './viewutils'; @@ -25,7 +25,7 @@ export function show(extensionId: string, json: boolean = false): Promise { console.log(JSON.stringify(extension, undefined, '\t')); } else { if (extension === undefined) { - console.log(`Error: Extension "${extensionId}" not found.`); + console.log(`${ERROR} Extension "${extensionId}" not found.`); } else { showOverview(extension); } @@ -61,7 +61,7 @@ function showOverview({ averagerating = 0, ratingcount = 0, } = statistics - .reduce((map, { statisticName, value }) => ({ ...map, [statisticName]: value }), {}); + .reduce((map, { statisticName, value }) => ({ ...map, [statisticName]: value }), {}); // Render console.log([ diff --git a/src/store.ts b/src/store.ts index e4cc6ec6..04b15ef3 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { home } from 'osenv'; -import { read, getGalleryAPI, getSecurityRolesAPI } from './util'; +import { read, getGalleryAPI, getSecurityRolesAPI, DONE } from './util'; import { validatePublisher } from './validation'; import * as denodeify from 'denodeify'; @@ -133,7 +133,7 @@ export function createPublisher(publisherName: string): Promise { .then(publisher => load().then(store => addPublisherToStore(store, publisher))); }); }) - .then(() => console.log(`Successfully created publisher '${publisherName}'.`)); + .then(() => console.log(`${DONE} Created publisher '${publisherName}'.`)); } export function deletePublisher(publisherName: string): Promise { @@ -143,7 +143,7 @@ export function deletePublisher(publisherName: string): Promise { .then(() => getGalleryAPI(pat)) .then(api => api.deletePublisher(publisherName)) .then(() => load().then(store => removePublisherFromStore(store, publisherName))) - .then(() => console.log(`Successfully deleted publisher '${publisherName}'.`)); + .then(() => console.log(`${DONE} Deleted publisher '${publisherName}'.`)); }); } diff --git a/src/util.ts b/src/util.ts index 9f019a7b..a368248c 100644 --- a/src/util.ts +++ b/src/util.ts @@ -2,6 +2,7 @@ import * as _read from 'read'; import { WebApi, getBasicHandler } from 'vso-node-api/WebApi'; import { IGalleryApi } from 'vso-node-api/GalleryApi'; import * as denodeify from 'denodeify'; +import chalk from 'chalk'; import { PublicGalleryAPI } from './publicgalleryapi'; import { ISecurityRolesApi } from 'vso-node-api/SecurityRolesApi'; @@ -95,4 +96,9 @@ export async function sequence(promiseFactories: { (): Promise }[]): Promis for (const factory of promiseFactories) { await factory(); } -} \ No newline at end of file +} + +export const DONE = chalk.bgGreen.black(' DONE '); +export const INFO = chalk.bgBlueBright.black(' INFO '); +export const WARN = chalk.bgYellow.black(' WARNING '); +export const ERROR = chalk.bgRed.black(' ERROR '); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bbd3329f..5bd6e9ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21,6 +21,13 @@ normalize-path "^2.0.1" through2 "^2.0.3" +"@types/chalk@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" + integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw== + dependencies: + chalk "*" + "@types/cheerio@^0.22.1": version "0.22.10" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.10.tgz#780d552467824be4a241b29510a7873a7432c4a6" @@ -98,6 +105,13 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -301,6 +315,15 @@ callsites@^0.2.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= +chalk@*, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -384,6 +407,18 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" @@ -2997,6 +3032,13 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"