Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.

Commit 783bf4a

Browse files
Nikhil-Vatssarthak-sehgal
authored andcommitted
Updated workflow, changed dummy prompts for tests (#17)
* Updated workflow for upgrading old components and making new components, changed dummy prompts in tests This adds the feature for importing old files if user chooses to upgrade an old component to a web component by implementing a new workflow. It also changes the tests to add a new dummy variable. * Added loader and version check This adds the loader for asynchronous tasks and checks version before showing the package directory URL to user. It also updates package.json to save the dependencies.
1 parent e24bf2e commit 783bf4a

File tree

4 files changed

+326
-7
lines changed

4 files changed

+326
-7
lines changed

__tests__/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const helpers = require("yeoman-test");
66
describe("generator-biojs-webcomponents:app", () => {
77
beforeAll(() => {
88
return helpers.run(path.join(__dirname, "../generators/app")).withPrompts({
9+
upgradeOrMake: "Make a new Web Component",
910
toolNameComputer: "test-component-tool",
1011
toolNameHuman: "Biojs test component"
1112
});
@@ -42,6 +43,7 @@ describe("generator-biojs-webcomponents:app", () => {
4243
return helpers
4344
.run(path.join(__dirname, "../generators/app"))
4445
.withPrompts({
46+
upgradeOrMake: "Make a new Web Component",
4547
toolNameComputer: "",
4648
toolNameHuman: ""
4749
})

generators/app/index.js

Lines changed: 267 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
const Generator = require("yeoman-generator");
33
const chalk = require("chalk");
44
const yosay = require("yosay");
5+
const { exec } = require("child_process");
6+
const ora = require("ora");
57

68
module.exports = class extends Generator {
79
initializing() {
@@ -10,7 +12,7 @@ module.exports = class extends Generator {
1012
});
1113
}
1214

13-
prompting() {
15+
async prompting() {
1416
// Have Yeoman greet the user.
1517
this.log(
1618
yosay(
@@ -20,7 +22,153 @@ module.exports = class extends Generator {
2022
)
2123
);
2224

23-
const prompts = [
25+
// First prompt
26+
const initialPrompts = [
27+
{
28+
type: "list",
29+
name: "upgradeOrMake",
30+
message: "What do you want to do today?",
31+
choices: [
32+
"Upgrade an existing component to a Web Component",
33+
"Make a new Web Component"
34+
],
35+
default: 0
36+
}
37+
];
38+
39+
// Secondary prompts if user chooses to upgrade an existing component to Web component.
40+
const upgradeComponentPrompts = [
41+
{
42+
type: "rawlist",
43+
name: "projectSource",
44+
message:
45+
"We need the build file (generally index.js, main.js or componentName.js) for this, import it using one of the options -",
46+
choices: [
47+
"Tell us the path of the file on your local machine and we will import it in the project.",
48+
"Tell us the npm package name, version, etc. and we will import it."
49+
],
50+
default: 0
51+
}
52+
];
53+
54+
// Prompts if user chooses to import file(s) using npm
55+
const npmPrompts = [
56+
{
57+
type: "input",
58+
name: "packageName",
59+
message: "Enter the package name (case sensitive).",
60+
validate: async function(props) {
61+
if (props) {
62+
let command = "npm view " + props;
63+
let res = await executeCommand(command, "packageName");
64+
return res;
65+
/**
66+
* Returns true if command is succesfully executed and hence yeoman proceeds to the next prompt
67+
* returns and logs the error if command execution fails
68+
*/
69+
}
70+
71+
return "This is a mandatory field, please answer."; // Warn user if no input is entered
72+
}
73+
},
74+
{
75+
type: "confirm",
76+
name: "packageNameConfirm",
77+
message: "Press enter if the package description shown is correct."
78+
},
79+
{
80+
type: "rawlist",
81+
name: "goBackOrGoAhead",
82+
message: "What do you want to do?",
83+
choices: [
84+
"Enter package name again.",
85+
"Import the file locally from your computer."
86+
],
87+
when: function(responses) {
88+
if (responses.packageNameConfirm) {
89+
return false; // Don't show this prompt, if user says that package description is correct.
90+
}
91+
92+
return true; // Show this prompt if user says that package description is not correct.
93+
}
94+
},
95+
{
96+
type: "input",
97+
name: "version",
98+
message:
99+
"Great! We will import the latest version of your file from the npm package, if you don't want this, enter the version.",
100+
default: "latest",
101+
when: function(responses) {
102+
if (responses.packageNameConfirm) {
103+
return true; // Show this prompt if user says that package description is correct
104+
}
105+
106+
return false; // Don't show this prompt if user says that package description is incorrect
107+
},
108+
validate: async function(props, answers) {
109+
let command = "npm view " + answers.packageName + "@" + props;
110+
var res = await executeCommand(command, "version");
111+
return res;
112+
}
113+
},
114+
{
115+
type: "input",
116+
name: "downloadURL",
117+
message: function(answers) {
118+
return (
119+
"This URL - " +
120+
chalk.bold.yellow(
121+
"https://www.jsdelivr.com/package/npm/" +
122+
answers.packageName +
123+
"?version=" +
124+
answers.version
125+
) +
126+
" contains the directory of the package, please find the build file (generally in the dist or build folder) and paste the link here, we will download it for you."
127+
);
128+
},
129+
when: function(responses) {
130+
if (responses.packageNameConfirm) {
131+
return true; // Show this prompt if user says that package description is correct
132+
}
133+
134+
return false; // Don't show this prompt if user says that package description is incorrect
135+
},
136+
validate: async function(props) {
137+
var res = await executeCommand(
138+
"mkdir dist && cd dist && curl -O " + props,
139+
"downloadURL"
140+
); // Import the build file in dist directory from npm
141+
return res;
142+
/**
143+
* Returns true if command execution is successful and proceeds to commonPrompts
144+
* returns and logs the error if execution fails
145+
*/
146+
}
147+
}
148+
];
149+
150+
// Prompt(s) if user chooses to import files locally from computer
151+
const localPrompts = [
152+
{
153+
type: "input",
154+
name: "pathOfBuildFile",
155+
message: "Please enter the path of the build file.",
156+
validate: async props => {
157+
var res = executeCommand(
158+
"mkdir dist && cp " + props + " dist",
159+
"local"
160+
); // Import the build file in dist directory locally from computer
161+
return res;
162+
/**
163+
* Returns true if command execution is successful and proceeds to commonPrompts
164+
* returns and logs the error if execution fails
165+
*/
166+
}
167+
}
168+
];
169+
170+
// Secondary prompts is user chooses to make a new component and final prompts if user chooses to upgrade an existing component
171+
const commonPrompts = [
24172
{
25173
type: "input",
26174
name: "toolNameComputer",
@@ -50,11 +198,83 @@ module.exports = class extends Generator {
50198
default: "BioJS component"
51199
}
52200
];
53-
return this.prompt(prompts).then(props => {
54-
// To access props later use this.props.someAnswer;
55-
this.props = props;
56-
this.props.toolNameCamel = toCamelCase(props.toolNameHuman);
57-
});
201+
202+
/** Interacts with the user using prompts
203+
* Recursive so that user can go to a previous step and/or change method of importing file
204+
* @param {string} repeatLocalOrNpmPrompts tells the generator which prompts should be shown again (localPrompts or npmPrompts)
205+
* @returns {Promise} to execute prompts and wait for there execution to finish
206+
*/
207+
const recursivePromptExecution = repeatLocalOrNpmPrompts => {
208+
// If user changes the method of importing later, recursive execution
209+
if (repeatLocalOrNpmPrompts) {
210+
// If user chooses to enter package name again when package description is incorrect
211+
if (repeatLocalOrNpmPrompts === npmPrompts[2].choices[0]) {
212+
return this.prompt(npmPrompts).then(props => {
213+
// If user chooses to go back and choose source of importing file again
214+
if (props.goBackOrGoAhead) {
215+
return recursivePromptExecution(props.goBackOrGoAhead); // Call the function recursively
216+
}
217+
218+
// If user chooses to import from npm after starting over
219+
return this.prompt(commonPrompts).then(props => {
220+
this.props = props;
221+
this.props.toolNameCamel = toCamelCase(props.toolNameHuman);
222+
});
223+
});
224+
}
225+
226+
// If user chooses to import file locally when package description is incorrect
227+
return this.prompt(localPrompts).then(() => {
228+
return this.prompt(commonPrompts).then(props => {
229+
this.props = props;
230+
this.props.toolNameCamel = toCamelCase(props.toolNameHuman);
231+
});
232+
});
233+
}
234+
235+
// Normal (initial) prompt execution
236+
return this.prompt(initialPrompts).then(props => {
237+
// To access props later use this.props.someAnswer;
238+
// If user chooses to upgrade an existing component
239+
if (props.upgradeOrMake === initialPrompts[0].choices[0]) {
240+
return this.prompt(upgradeComponentPrompts).then(props => {
241+
// If user chooses to import file locally from computer
242+
if (props.projectSource === upgradeComponentPrompts[0].choices[0]) {
243+
return this.prompt(localPrompts).then(() => {
244+
return this.prompt(commonPrompts).then(props => {
245+
this.props = props;
246+
this.props.toolNameCamel = toCamelCase(props.toolNameHuman);
247+
});
248+
});
249+
}
250+
251+
// If user chooses to import file from npm
252+
return this.prompt(npmPrompts).then(props => {
253+
// If user chooses to go back and choose source of importing file again
254+
if (props.goBackOrGoAhead) {
255+
return recursivePromptExecution(props.goBackOrGoAhead); // Call the function recursively
256+
}
257+
258+
// If user chooses to import from npm initially
259+
return this.prompt(commonPrompts).then(props => {
260+
this.props = props;
261+
this.props.toolNameCamel = toCamelCase(props.toolNameHuman);
262+
});
263+
});
264+
});
265+
}
266+
267+
// If user chooses to make a new component
268+
if (props.upgradeOrMake === initialPrompts[0].choices[1]) {
269+
return this.prompt(commonPrompts).then(props => {
270+
this.props = props;
271+
this.props.toolNameCamel = toCamelCase(props.toolNameHuman);
272+
});
273+
}
274+
});
275+
};
276+
277+
await recursivePromptExecution(); // Wait for the function execution to finish
58278
}
59279

60280
writing() {
@@ -173,3 +393,43 @@ function toCamelCase(aString) {
173393
});
174394
return camelString;
175395
}
396+
397+
/**
398+
* Executes command in terminal and returns the output or error
399+
* @param {string} command the command to be executed
400+
* @param {string} type whether the command is related to npm or not
401+
* @returns {Promise}, resolves and returns true if execution is successful, rejects and returns error otherwise.
402+
*/
403+
function executeCommand(command, type) {
404+
const spinner = ora({
405+
text: "Loading..",
406+
spinner: "weather"
407+
});
408+
spinner.start();
409+
return new Promise((resolve, reject) => {
410+
exec(command, (err, stdout) => {
411+
if (err) {
412+
// The command couldn't be executed
413+
spinner.stop();
414+
reject(err);
415+
} else if (type === "version") {
416+
// Command successfully executed
417+
if (stdout) {
418+
spinner.stop();
419+
resolve(true);
420+
} else {
421+
spinner.stop();
422+
let err = "Sorry, that version does not exist!";
423+
reject(err);
424+
}
425+
} else if (stdout) {
426+
process.stdout.write(`\n ${stdout} \n`); // If there is an output display it
427+
spinner.stop();
428+
resolve(true);
429+
} else {
430+
spinner.stop();
431+
resolve(true);
432+
}
433+
});
434+
});
435+
}

0 commit comments

Comments
 (0)