Skip to content

Commit

Permalink
feat: create new amplify-prompts package to handle all terminal inter…
Browse files Browse the repository at this point in the history
…actions (aws-amplify#7774)

* feat: working on prompts package

* feat: add list picker methods

* feat: autocomplete for all pick types

* feat: fancy types

* test: restructure interface a bit and scaffold unit tests

* test: adding a bunch of tests

* chore: mark deprecated methods / functions

* chore: adding some comments

* Update packages/amplify-prompts/src/__tests__/prompter.test.ts

Co-authored-by: John Hockett <[email protected]>

* chore: rename multiselect => multiSelect

* feat: better support for --yes and support input list

* fix: use EOL as line ending

Co-authored-by: John Hockett <[email protected]>
  • Loading branch information
2 people authored and marcvberg committed Oct 13, 2021
1 parent bb039b8 commit 6c93be3
Show file tree
Hide file tree
Showing 20 changed files with 1,056 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ packages/amplify-migration-tests/amplify-migration-reports
packages/amplify-migration-tests/lib
packages/amplify-headless-interface/lib
packages/amplify-provider-awscloudformation/lib
packages/amplify-prompts/lib
packages/amplify-util-import/lib
packages/amplify-util-headless-input/lib
packages/*/node_modules
Expand Down
39 changes: 39 additions & 0 deletions packages/amplify-cli-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export type $TSAny = any;
// Use it for all CLI Context class references, it enables a quick way to see what we have on the context
export type $TSContext = {
amplify: AmplifyToolkit;
/**
* @deprecated Use printer from package amplify-prompts instead
*/
print: IContextPrint;
migrationInfo: $TSAny;
projectHasMobileHubResources: boolean;
Expand All @@ -49,16 +52,49 @@ export type CategoryName = string;
export type ResourceName = string;

export type IContextPrint = {
/**
* @deprecated Use printer.info from amplify-prommpts instead
*/
info: (message: string) => void;
/**
* @deprecated Why are you using this? If you really need it, implement it in amplify-prompts printer.ts
*/
fancy: (message?: string) => void;
/**
* @deprecated Use printer.warn from amplify-prompts instead
*/
warning: (message: string) => void;
/**
* @deprecated Use printer.error from amplify-prompts instead
*/
error: (message: string) => void;
/**
* @deprecated Use printer.success from amplify-prommpts instead
*/
success: (message: string) => void;
/**
* @deprecated The next time we refactor code that uses this function, refactor the table function into formatter.ts from amplify-prompts and use that instead
*/
table: (data: string[][], options?: { format?: 'markdown' | 'lean' }) => void;
/**
* @deprecated Use printer.debug from amplify-prompts instead
*/
debug: (message: string) => void;
/**
* @deprecated Use printer.info from amplify-prompts and specify color
*/
green: (message: string) => void;
/**
* @deprecated Use printer.info from amplify-prompts and specify color
*/
yellow: (message: string) => void;
/**
* @deprecated Use printer.info from amplify-prompts and specify color
*/
red: (message: string) => void;
/**
* @deprecated Use printer.info from amplify-prompts and specify color
*/
blue: (message: string) => void;
};

Expand Down Expand Up @@ -188,6 +224,9 @@ interface AmplifyToolkit {
getResourceStatus: (category?: $TSAny, resourceName?: $TSAny, providerName?: $TSAny, filteredResources?: $TSAny) => $TSAny;
getResourceOutputs: () => $TSAny;
getWhen: () => $TSAny;
/**
* @deprecated Use validators from amplify-prompts or add a new validator in that module
*/
inputValidation: (input: $TSAny) => (value: $TSAny) => boolean | string;
listCategories: () => $TSAny;
makeId: (n?: number) => string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import * as inquirer from 'inquirer';

/**
* @deprecated Use confirmContinue from ammplify-prompts instead
*/
export async function confirmPrompt(message: string, defaultValue = true) {
const ans = await inquirer.prompt({
name: 'yesno',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/**
* @deprecated Use validators from amplify-prompts or add a new validator to that module
* question is either of the legacy form:
* {
* validation: {
Expand Down
18 changes: 18 additions & 0 deletions packages/amplify-cli/src/extensions/amplify-helpers/print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,37 @@ type CLIPrintColors = typeof importedColors & {

const colors = importedColors as CLIPrintColors;

/**
* @deprecated Use printer.info from amplify-prompts instead
*/
function info(message) {
console.log(colors.info(message));
}

/**
* @deprecated Use printer.warn from amplify-prompts instead
*/
function warning(message) {
console.log(colors.warning(message));
}

/**
* @deprecated Use printer.error from amplify-prompts instead
*/
function error(message) {
console.log(colors.error(message));
}

/**
* @deprecated Use printer.success from amplify-prompts instead
*/
function success(message) {
console.log(colors.success(message));
}

/**
* @deprecated Use printer.debug from amplify-prompts instead
*/
function debug(message, title = 'DEBUG') {
const topLine = `vvv -----[ ${title} ]----- vvv`;
const botLine = `^^^ -----[ ${title} ]----- ^^^`;
Expand All @@ -46,6 +61,9 @@ function debug(message, title = 'DEBUG') {
console.log(colors.rainbow(botLine));
}

/**
* @deprecated The next time we refactor code that uses this function, refactor the table function into formatter.ts from amplify-prompts and use that instead
*/
function table(data, options: any = {}) {
let t: CLITable.Table;
switch (options.format) {
Expand Down
7 changes: 7 additions & 0 deletions packages/amplify-prompts/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
},
};
35 changes: 35 additions & 0 deletions packages/amplify-prompts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "amplify-prompts",
"version": "1.0.0",
"description": "Utility functions for Amplify CLI terminal I/O",
"main": "lib/index.js",
"scripts": {
"build": "tsc",
"clean": "rimraf lib tsconfig.tsbuildinfo",
"demo": "yarn build && node lib/demo/demo.js",
"test": "jest",
"watch": "tsc -w"
},
"repository": {
"type": "git",
"url": "git+https://github.com/aws-amplify/amplify-cli.git"
},
"keywords": [
"amplify",
"cli",
"prompts"
],
"author": "Amazon Web Services",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/aws-amplify/amplify-cli/issues"
},
"homepage": "https://github.com/aws-amplify/amplify-cli#readme",
"dependencies": {
"chalk": "^4.1.1",
"enquirer": "^2.3.6"
},
"devDependencies": {
"rimraf": "^3.0.2"
}
}
17 changes: 17 additions & 0 deletions packages/amplify-prompts/src/__tests__/formatter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { printer } from '../printer';
import { formatter } from '../formatter';

jest.mock('../printer');

const printer_mock = printer as jest.Mocked<typeof printer>;

describe('list', () => {
beforeEach(jest.clearAllMocks);
it('prints list items at info level', () => {
const items = ['item1', 'item2'];
formatter.list(items);
expect(printer_mock.info.mock.calls.length).toBe(2);
expect(printer_mock.info.mock.calls[0][0]).toMatchInlineSnapshot(`"- item1"`);
expect(printer_mock.info.mock.calls[1][0]).toMatchInlineSnapshot(`"- item2"`);
});
});
112 changes: 112 additions & 0 deletions packages/amplify-prompts/src/__tests__/printer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { AmplifyPrinter } from '../printer';
import os from 'os';
import * as flags from '../flags';
const writeStream_stub = ({
write: jest.fn(),
} as unknown) as jest.Mocked<NodeJS.WritableStream>;

jest.mock('../flags');
jest.mock('os');

type Writeable<T> = { -readonly [P in keyof T]: T[P] };

const flags_mock = flags as jest.Mocked<Writeable<typeof flags>>;

const testInput = 'this is a test line';

const printer = new AmplifyPrinter(writeStream_stub);

const os_mock = os as jest.Mocked<Writeable<typeof os>>;

os_mock.EOL = '\n';

beforeEach(() => {
jest.clearAllMocks();
flags_mock.isDebug = false;
flags_mock.isSilent = false;
flags_mock.isYes = false;
});

it('prints debug lines when debug flag is set', () => {
flags_mock.isDebug = true;
printer.debug(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"this is a test line
"
`);
});

it('does not print debug lines by default', () => {
printer.debug(testInput);
expect(writeStream_stub.write.mock.calls.length).toBe(0);
});

it('prints info line by default', () => {
printer.info(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"this is a test line
"
`);
});

it('prints info line in specified color', () => {
printer.info(testInput, 'blue');
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"this is a test line
"
`);
});

it('does not print info line when silent flag is set', () => {
flags_mock.isSilent = true;
printer.info(testInput);
expect(writeStream_stub.write.mock.calls.length).toBe(0);
});

it('prints success line by default', () => {
printer.success(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"✅ this is a test line
"
`);
});

it('does not print success line when silent flag is set', () => {
flags_mock.isSilent = true;
printer.success(testInput);
expect(writeStream_stub.write.mock.calls.length).toBe(0);
});

it('prints warn line by default', () => {
printer.warn(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"⚠️ this is a test line
"
`);
});

it('prints warn line when silent flag is set', () => {
flags_mock.isSilent = true;
printer.warn(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"⚠️ this is a test line
"
`);
});

it('prints error line by default', () => {
printer.error(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"🛑 this is a test line
"
`);
});

it('prints error line when silent flag is set', () => {
flags_mock.isSilent = true;
printer.error(testInput);
expect(writeStream_stub.write.mock.calls[0][0]).toMatchInlineSnapshot(`
"🛑 this is a test line
"
`);
});
Loading

0 comments on commit 6c93be3

Please sign in to comment.