Skip to content

Commit

Permalink
JavaScript (v3): Add example scenario.
Browse files Browse the repository at this point in the history
  • Loading branch information
cpyle0819 committed Oct 18, 2023
1 parent c2e4fdb commit b1323ba
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 13 deletions.
8 changes: 0 additions & 8 deletions javascriptv3/example_code/libs/prompter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,17 @@
import { select, input, confirm, checkbox } from "@inquirer/prompts";

export class Prompter {
spacer() {
console.log("\n");
}

/**
* @param {{ message: string, choices: { name: string, value: string }[]}} options
*/
select(options) {
this.spacer();
return select(options);
}

/**
* @param {{ message: string }} options
*/
input(options) {
this.spacer();
return input(options);
}

Expand All @@ -42,15 +36,13 @@ export class Prompter {
* @param {{ message: string }} options
*/
confirm(options) {
this.spacer();
return confirm(options);
}

/**
* @param {{ message: string, choices: { name: string, value: string }[]}} options
*/
checkbox(options) {
this.spacer();
return checkbox(options);
}
}
Expand Down
103 changes: 103 additions & 0 deletions javascriptv3/example_code/libs/scenario-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import {
Scenario,
ScenarioAction,
ScenarioInput,
ScenarioOutput,
} from "@aws-sdk-examples/libs/scenario.js";

const greet = new ScenarioOutput(
"greet",
"Hi! This is a scenario. It can handle your " + "inputs and outputs.",
);

const describeInput = new ScenarioOutput(
"describe input",
"ScenarioInput collects three different types of input from the user: " +
"plain text, single-selection, and multi-selection. Let's look at some examples.",
);

const getFoods = new ScenarioInput("foods", "Choose your favorite foods.", {
type: "multi-select",
choices: ["sushi", "pizza", "hamburger"],
});

const getAge = new ScenarioInput(
"age",
"Select your age range (my apologies if you're younger or older than the provided ranges):",
{ type: "select", choices: ["18-30", "31-50", "50-100"] },
);

const getName = new ScenarioInput("name", "What's your name?", {
type: "input",
});

const describeOutput = new ScenarioOutput(
"describe output",
"ScenarioOutput can log a raw string or build " +
"dynamic output using the input from previous steps. " +
"You've already seen several raw string examples in the preceding output. " +
"The dynamic output is generated with a function that takes a context " +
"object that tracks input values. Here's some dynamic output: ",
);

const dynamicOutput = new ScenarioOutput(
"dynamicOutput",
/**
* @param {{ "foods": string[] }} c
*/
(c) =>
`Hi, ${c.name}! You are between the ages of ${c.age}. ` +
`Your favorite foods are: ${c.foods.join(", ")}.`,
);

const describeActions = new ScenarioOutput(
"describe actions",
"ScenarioActions let you run a function. The function is passed the same context " +
"as the dynamic output. You can modify the context here if you like, do asynchronous tasks, " +
"or anything else you'd like to do. Actions don't log anything on their own, but you should use " +
"ScenarioOutput to do that. The next step will run a 'reverse name' action and then run the " +
"dynamic output step again.",
);

const reverseName = new ScenarioAction(
"reverse name",
/**
* @param {{ name: string }} c
*/
(c) => {
c.name = c.name.split("").reverse().join("");
},
);

const summary = new ScenarioOutput(
"summary",
"That's all there is too it! Thanks for checking it out.",
);

const confirmExit = new ScenarioInput(
"quit",
"Enter anything (or nothing) to exit.",
{ type: "confirm" },
);

const myScenario = new Scenario("My Scenario", [
greet,
describeInput,
getFoods,
getAge,
getName,
describeOutput,
dynamicOutput,
describeActions,
reverseName,
dynamicOutput,
summary,
confirmExit,
]);

await myScenario.run();
32 changes: 27 additions & 5 deletions javascriptv3/example_code/libs/scenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ class Step {
constructor(name) {
this.name = name;
}

/**
* Alias for "name".
*/
get key() {
return this.name;
}
}

export class ScenarioOutput extends Step {
Expand All @@ -36,16 +43,18 @@ export class ScenarioOutput extends Step {
async handle(context) {
const output =
typeof this.value === "function" ? this.value(context) : this.value;
const paddingTop = "\n";
const paddingBottom = "\n";
const logger = this.options.slow ? this.slowLogger : this.logger;
await logger.log(JSON.stringify(output));
await logger.log(paddingTop + output + paddingBottom);
}
}

export class ScenarioInput extends Step {
/**
* @param {string} name
* @param {string} prompt
* @param {{ type: "input" | "multi-select" | "select", choices: { name: string, value: string }[]} options
* @param {{ type: "confirm" | "input" | "multi-select" | "select", choices: (string | { name: string, value: string })[]} options
*/
constructor(name, prompt, options) {
super(name);
Expand All @@ -58,18 +67,27 @@ export class ScenarioInput extends Step {
* @param {Record<string, any>} context
*/
async handle(context) {
const choices =
this.options.choices && typeof this.options.choices[0] === "string"
? this.options.choices.map((s) => ({ name: s, value: s }))
: this.options.choices;

if (this.options.type === "multi-select") {
context[this.name] = await this.prompter.checkbox({
message: this.prompt,
choices: this.options.choices,
choices,
});
} else if (this.options.type === "select") {
context[this.name] = await this.prompter.select({
message: this.prompt,
choices: this.options.choices,
choices,
});
} else if (this.options.type === "input") {
context[this.name] = await this.prompter.input({ message: this.prompt });
} else if (this.options.type === "confirm") {
context[this.name] = await this.prompter.confirm({
message: this.prompt,
});
} else {
throw new Error(
`Error handling ScenarioInput, ${this.options.type} is not supported.`,
Expand Down Expand Up @@ -101,10 +119,14 @@ export class Scenario {
context = {};

/**
* @param {string} name
* @param {(ScenarioOutput | ScenarioInput | ScenarioAction)[]} steps
* @param {Record<string, any>} initialContext
*/
constructor(steps = []) {
constructor(name, steps = [], initialContext = {}) {
this.name = name;
this.steps = steps;
this.context = { ...initialContext, name };
}

async run() {
Expand Down

0 comments on commit b1323ba

Please sign in to comment.