dceky 1.0.0-beta-profile.1 → 1.0.0-beta-yuenler.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/lib/commands/assertDoesNotHaveClass.d.ts +19 -0
  2. package/lib/commands/assertDoesNotHaveClass.js +17 -0
  3. package/lib/commands/assertDoesNotHaveClass.js.map +1 -0
  4. package/lib/commands/assertHasClass.d.ts +19 -0
  5. package/lib/commands/assertHasClass.js +17 -0
  6. package/lib/commands/assertHasClass.js.map +1 -0
  7. package/lib/commands/assertNumElements.d.ts +19 -0
  8. package/lib/commands/assertNumElements.js +17 -0
  9. package/lib/commands/assertNumElements.js.map +1 -0
  10. package/lib/commands/clickWithRetry.d.ts +16 -0
  11. package/lib/commands/clickWithRetry.js +29 -0
  12. package/lib/commands/clickWithRetry.js.map +1 -0
  13. package/lib/commands/getNumElements.d.ts +15 -0
  14. package/lib/commands/getNumElements.js +19 -0
  15. package/lib/commands/getNumElements.js.map +1 -0
  16. package/lib/commands/handleHarvardKey.d.ts +14 -0
  17. package/lib/commands/handleHarvardKey.js +58 -0
  18. package/lib/commands/handleHarvardKey.js.map +1 -0
  19. package/lib/commands/launchAs.d.ts +23 -0
  20. package/lib/commands/launchAs.js +65 -0
  21. package/lib/commands/launchAs.js.map +1 -0
  22. package/lib/commands/launchLTIUsingToken.d.ts +16 -0
  23. package/lib/commands/launchLTIUsingToken.js +57 -0
  24. package/lib/commands/launchLTIUsingToken.js.map +1 -0
  25. package/lib/commands/navigateToHref.d.ts +20 -0
  26. package/lib/commands/navigateToHref.js +23 -0
  27. package/lib/commands/navigateToHref.js.map +1 -0
  28. package/lib/commands/runScript.d.ts +17 -0
  29. package/lib/commands/runScript.js +25 -0
  30. package/lib/commands/runScript.js.map +1 -0
  31. package/lib/commands/typeInto.d.ts +21 -0
  32. package/lib/commands/typeInto.js +28 -0
  33. package/lib/commands/typeInto.js.map +1 -0
  34. package/lib/commands/visitCanvasGETEndpoint.d.ts +20 -0
  35. package/lib/commands/visitCanvasGETEndpoint.js +26 -0
  36. package/lib/commands/visitCanvasGETEndpoint.js.map +1 -0
  37. package/lib/commands/waitForElementVisible.d.ts +15 -0
  38. package/lib/commands/waitForElementVisible.js +20 -0
  39. package/lib/commands/waitForElementVisible.js.map +1 -0
  40. package/lib/index.js +1 -0
  41. package/lib/index.js.map +1 -1
  42. package/lib/init.d.ts +4 -11
  43. package/lib/init.js +35 -4
  44. package/lib/init.js.map +1 -1
  45. package/package.json +4 -20
  46. package/src/commands/assertDoesNotHaveClass.ts +40 -0
  47. package/src/commands/assertHasClass.ts +40 -0
  48. package/src/commands/assertNumElements.ts +37 -0
  49. package/src/commands/clickWithRetry.ts +51 -0
  50. package/src/commands/getNumElements.ts +38 -0
  51. package/src/commands/handleHarvardKey.ts +87 -0
  52. package/src/commands/launchAs.ts +104 -0
  53. package/src/commands/launchLTIUsingToken.ts +84 -0
  54. package/src/commands/navigateToHref.ts +45 -0
  55. package/src/commands/runScript.ts +42 -0
  56. package/src/commands/typeInto.ts +57 -0
  57. package/src/commands/visitCanvasGETEndpoint.ts +48 -0
  58. package/src/commands/waitForElementVisible.ts +40 -0
  59. package/src/genConfiguration.ts +11 -0
  60. package/src/index.ts +2 -7
  61. package/src/init.ts +26 -2
  62. package/tsconfig.json +0 -1
  63. package/docs/GlobalsAndProfiles.md +0 -23
  64. package/profileChooser/chooseProfile.ts +0 -35
  65. package/profileChooser/helpers/print.ts +0 -155
  66. package/profileChooser/helpers/prompt.ts +0 -23
  67. package/profileChooser/helpers/showChooser.ts +0 -95
  68. package/profileChooser/types/ChooserOption.ts +0 -11
  69. package/src/commands/clickSomething.ts +0 -33
  70. package/src/genConfiguration/helpers/resolveDependents.ts +0 -47
  71. package/src/genConfiguration/helpers/splitEnv.ts +0 -30
  72. package/src/genConfiguration/index.ts +0 -83
  73. package/src/genConfiguration/types/DependentValue.ts +0 -14
  74. package/src/genConfiguration/types/GlobalsOrProfile.ts +0 -12
  75. package/src/genConfiguration/types/SplitEnv.ts +0 -18
@@ -0,0 +1,84 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Log into Canvas using an access token and launch an LTI app
12
+ * @param accessToken the user's Canvas access token
13
+ * @param courseId the Canvas ID of the course to launch from
14
+ * @param appName the name of the app as it appears in the course's left-hand nav
15
+ * @example cy.launchLTIUsingToken('your_access_token', 12345, 'My LTI App')
16
+ */
17
+ launchLTIUsingToken(accessToken: string, courseId: number, appName: string): Chainable<void>;
18
+ }
19
+ }
20
+ }
21
+
22
+ /*----------------------------------------*/
23
+ /* --------------- Command -------------- */
24
+ /*----------------------------------------*/
25
+
26
+ const launchLTIUsingToken = () => {
27
+ Cypress.Commands.add('launchLTIUsingToken', (accessToken: string, courseId: number, appName: string) => {
28
+ cy.log(`Launch LTI app "${appName}" in course ${courseId} using access token`);
29
+
30
+ // Get the external tools for the course
31
+ cy.visitCanvasGETEndpoint({
32
+ path: `/courses/${courseId}/external_tools`,
33
+ accessToken: accessToken
34
+ }).then((externalTools: any[]) => {
35
+ cy.log(`Found ${externalTools.length} external tools`);
36
+
37
+ // Find the external tool of interest
38
+ let toolId = 0;
39
+
40
+ for (const externalTool of externalTools) {
41
+ // Skip non-nav items
42
+ if (!externalTool.course_navigation || typeof externalTool.course_navigation !== 'object') {
43
+ continue;
44
+ }
45
+
46
+ // Skip non-labeled items
47
+ if (!externalTool.course_navigation.text) {
48
+ continue;
49
+ }
50
+
51
+ // Check if this app matches the name
52
+ const thisAppName = externalTool.course_navigation.text.trim().toLowerCase();
53
+ if (thisAppName === appName.trim().toLowerCase()) {
54
+ toolId = externalTool.id;
55
+ cy.log(`Found matching app: "${externalTool.course_navigation.text}" with ID ${toolId}`);
56
+ break;
57
+ }
58
+ }
59
+
60
+ // Make sure we found the app
61
+ if (toolId === 0) {
62
+ throw new Error(`Could not find any apps named "${appName}" in course ${courseId}`);
63
+ }
64
+
65
+ // Get a sessionless launch URL
66
+ cy.visitCanvasGETEndpoint({
67
+ path: `/courses/${courseId}/external_tools/sessionless_launch?id=${toolId}`,
68
+ accessToken: accessToken
69
+ }).then((sessionlessLaunchInfo: any) => {
70
+ const launchURL = sessionlessLaunchInfo.url;
71
+ cy.log(`Launching LTI app at: ${launchURL}`);
72
+
73
+ // Launch the tool
74
+ cy.visit(launchURL);
75
+ });
76
+ });
77
+ });
78
+ };
79
+
80
+ /*----------------------------------------*/
81
+ /* --------------- Export --------------- */
82
+ /*----------------------------------------*/
83
+
84
+ export default launchLTIUsingToken;
@@ -0,0 +1,45 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Navigate to href attribute of Harvard identity provider button
12
+ * @param opts object containing all arguments
13
+ * @param opts.item the CSS selector of interest
14
+ * @param opts.domain the domain of the page
15
+ * @returns The full URL constructed from the href
16
+ * @example cy.navigateToHref({ item: '#login-button', domain: 'https://example.com' })
17
+ */
18
+ navigateToHref(opts: { item: string; domain: string }): Chainable<string>;
19
+ }
20
+ }
21
+ }
22
+
23
+ /*----------------------------------------*/
24
+ /* --------------- Command -------------- */
25
+ /*----------------------------------------*/
26
+
27
+ const navigateToHref = () => {
28
+ Cypress.Commands.add('navigateToHref', (opts: { item: string; domain: string }) => {
29
+ const { item, domain } = opts;
30
+
31
+ cy.waitForElementVisible(item);
32
+ return cy
33
+ .get(item)
34
+ .invoke('attr', 'href')
35
+ .then((href: any) => {
36
+ return domain + href;
37
+ });
38
+ });
39
+ };
40
+
41
+ /*----------------------------------------*/
42
+ /* --------------- Export --------------- */
43
+ /*----------------------------------------*/
44
+
45
+ export default navigateToHref;
@@ -0,0 +1,42 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Run a script on the page
12
+ * @param scriptLines the script to run in an anonymous function on the page.
13
+ * If multiple script arguments are included, each argument will be considered a
14
+ * new line of the script.
15
+ * @returns return value of the script
16
+ * @example cy.runScript('console.log("Hello");', 'return document.title;')
17
+ */
18
+ runScript(...scriptLines: string[]): Chainable<any>;
19
+ }
20
+ }
21
+ }
22
+
23
+ /*----------------------------------------*/
24
+ /* --------------- Command -------------- */
25
+ /*----------------------------------------*/
26
+
27
+ const runScript = () => {
28
+ Cypress.Commands.add('runScript', (...scriptLines: string[]) => {
29
+ cy.log('Running script');
30
+ const fullScript = scriptLines.join('\n');
31
+ return cy.window().then((win: any) => {
32
+ const result = win.eval(fullScript);
33
+ return cy.wrap(result);
34
+ });
35
+ });
36
+ };
37
+
38
+ /*----------------------------------------*/
39
+ /* --------------- Export --------------- */
40
+ /*----------------------------------------*/
41
+
42
+ export default runScript;
@@ -0,0 +1,57 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Type text into an element. This function first removes the previous text in the element
12
+ * @param opts object containing all arguments
13
+ * @param opts.item the CSS selector of interest
14
+ * @param opts.text the text to type
15
+ * @param opts.pressEnter if true, after typing into the text field, simulate pressing enter
16
+ * @example cy.typeInto({ item: '#username', text: 'john_doe', pressEnter: false })
17
+ */
18
+ typeInto(opts: {
19
+ item: string;
20
+ text: string;
21
+ pressEnter?: boolean;
22
+ }): Chainable<Element>;
23
+ }
24
+ }
25
+ }
26
+
27
+ /*----------------------------------------*/
28
+ /* --------------- Command -------------- */
29
+ /*----------------------------------------*/
30
+
31
+ const typeInto = () => {
32
+ Cypress.Commands.add('typeInto', (opts: { item: string; text: string; pressEnter?: boolean }) => {
33
+ const { item, text, pressEnter } = opts;
34
+ cy.log(`Type "${text}" into ${item}`);
35
+
36
+ // Check if the text contains an enter key press
37
+ const enterAtEndOfText = text.charAt(text.length - 1) === '\n';
38
+
39
+ // Type the text without a trailing enter if there was one
40
+ const textWithoutTrailingEnter = enterAtEndOfText
41
+ ? text.substring(0, text.length - 1)
42
+ : text;
43
+
44
+ cy.get(item).clear().type(textWithoutTrailingEnter);
45
+
46
+ // Press enter if explicitly requested or if text ended with newline
47
+ if (pressEnter || enterAtEndOfText) {
48
+ cy.get(item).type('{enter}');
49
+ }
50
+ });
51
+ };
52
+
53
+ /*----------------------------------------*/
54
+ /* --------------- Export --------------- */
55
+ /*----------------------------------------*/
56
+
57
+ export default typeInto;
@@ -0,0 +1,48 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Makes a GET request to Canvas API endpoint
12
+ * @param opts object containing all arguments
13
+ * @param opts.path The API path (e.g., '/courses', '/users/self')
14
+ * @param opts.accessToken The Canvas access token
15
+ * @returns The API response body
16
+ * @example cy.visitCanvasGETEndpoint({ path: '/courses', accessToken: 'your_token' })
17
+ */
18
+ visitCanvasGETEndpoint(opts: { path: string; accessToken: string }): Chainable<any>;
19
+ }
20
+ }
21
+ }
22
+
23
+ /*----------------------------------------*/
24
+ /* --------------- Command -------------- */
25
+ /*----------------------------------------*/
26
+
27
+ const visitCanvasGETEndpoint = () => {
28
+ Cypress.Commands.add('visitCanvasGETEndpoint', (opts: { path: string; accessToken: string }) => {
29
+ cy.log('Visiting Canvas GET endpoint');
30
+ const { path, accessToken } = opts;
31
+
32
+ cy.log('Canvas API: ' + path);
33
+ return cy.request({
34
+ method: 'GET',
35
+ url: 'https://canvas.harvard.edu/api/v1' + path,
36
+ qs: {
37
+ per_page: 200,
38
+ access_token: accessToken
39
+ }
40
+ }).its('body');
41
+ });
42
+ };
43
+
44
+ /*----------------------------------------*/
45
+ /* --------------- Export --------------- */
46
+ /*----------------------------------------*/
47
+
48
+ export default visitCanvasGETEndpoint;
@@ -0,0 +1,40 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Wait for an element to be visible
12
+ * @param item the CSS selector of interest
13
+ * @param timeoutSec the number of seconds to wait before timing out (default: 10)
14
+ * @example cy.waitForElementVisible('#submit-button', 15)
15
+ */
16
+ waitForElementVisible(item: string, timeoutSec?: number): Chainable<JQuery<HTMLElement>>;
17
+ }
18
+ }
19
+ }
20
+
21
+ /*----------------------------------------*/
22
+ /* --------------- Command -------------- */
23
+ /*----------------------------------------*/
24
+
25
+ const waitForElementVisible = () => {
26
+ Cypress.Commands.add('waitForElementVisible', (item: string, timeoutSec?: number) => {
27
+ cy.log('Waiting for element to be visible');
28
+ timeoutSec = timeoutSec || 10;
29
+
30
+ const timeoutMs = timeoutSec * 1000;
31
+ cy.log(`Wait for ${item} to be visible`);
32
+ return cy.get(item, { timeout: timeoutMs }).should('be.visible');
33
+ });
34
+ };
35
+
36
+ /*----------------------------------------*/
37
+ /* --------------- Export --------------- */
38
+ /*----------------------------------------*/
39
+
40
+ export default waitForElementVisible;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Generate Cypress configuration based on global credentials,
3
+ * variables, resources, and profiles
4
+ * @author Yuen Ler Chow
5
+ * ...
6
+ */
7
+ const genConfiguration = () => {
8
+ return {};
9
+ };
10
+
11
+ export default genConfiguration;
package/src/index.ts CHANGED
@@ -2,16 +2,11 @@
2
2
  import init from './init';
3
3
  import genConfiguration from './genConfiguration';
4
4
 
5
- // Import types
6
- import GlobalsOrProfile from './genConfiguration/types/GlobalsOrProfile';
7
-
8
5
  // Automatically initialize upon importing the library
9
6
  init();
10
7
 
8
+ // Export key functions
11
9
  export {
12
- // Helpers
13
- init,
14
10
  genConfiguration,
15
- // Types
16
- GlobalsOrProfile,
11
+ init,
17
12
  };
package/src/init.ts CHANGED
@@ -1,5 +1,17 @@
1
1
  // Import all commands
2
- import clickSomething from './commands/clickSomething';
2
+ import assertDoesNotHaveClass from './commands/assertDoesNotHaveClass';
3
+ import assertHasClass from './commands/assertHasClass';
4
+ import assertNumElements from './commands/assertNumElements';
5
+ import clickWithRetry from './commands/clickWithRetry';
6
+ import getNumElements from './commands/getNumElements';
7
+ import handleHarvardKey from './commands/handleHarvardKey';
8
+ import launchAs from './commands/launchAs';
9
+ import launchLTIUsingToken from './commands/launchLTIUsingToken';
10
+ import navigateToHref from './commands/navigateToHref';
11
+ import runScript from './commands/runScript';
12
+ import typeInto from './commands/typeInto';
13
+ import visitCanvasGETEndpoint from './commands/visitCanvasGETEndpoint';
14
+ import waitForElementVisible from './commands/waitForElementVisible';
3
15
 
4
16
  /**
5
17
  * Initialize custom commands
@@ -7,7 +19,19 @@ import clickSomething from './commands/clickSomething';
7
19
  */
8
20
  const init = () => {
9
21
  // Execute each command adder
10
- clickSomething();
22
+ assertDoesNotHaveClass();
23
+ assertHasClass();
24
+ assertNumElements();
25
+ clickWithRetry();
26
+ getNumElements();
27
+ handleHarvardKey();
28
+ launchAs();
29
+ launchLTIUsingToken();
30
+ navigateToHref();
31
+ runScript();
32
+ typeInto();
33
+ visitCanvasGETEndpoint();
34
+ waitForElementVisible();
11
35
  };
12
36
 
13
37
  export default init;
package/tsconfig.json CHANGED
@@ -8,7 +8,6 @@
8
8
  "declaration": true,
9
9
  "sourceMap": true,
10
10
  "target": "es5",
11
- "lib": ["es5", "es2015.promise", "es2017.object"],
12
11
  "outDir": "./lib"
13
12
  },
14
13
  "include": [
@@ -1,23 +0,0 @@
1
- # Globals and Profiles Configuration
2
-
3
- ### Configuration Setup
4
-
5
- The configuration setup involves the following steps:
6
-
7
- 1. Split each globals/profiles map into two: `basic` values and `dependsOn` values.
8
- 2. Merge all `basic` values into a running env object (in order so last ones processed are the highest priority).
9
- 3. Go through each `dependsOn` value, look up the value it depends on in the running env object.
10
- 4. Add `dependsOn` values into the running env object (in order so last ones processed are the highest priority).
11
- 5. Wrap the env object into a config.
12
-
13
- ### Assumptions
14
-
15
- * `dependsOn` values must depend on a basic `value`, not on another `dependsOn` value.
16
-
17
- ### DependsOn Value
18
-
19
- The `dependsOn` value is an object that has the following structure:
20
-
21
- * `dependsOn`: the key of the `basic` value that we are depending on
22
- * `value`: the value that we are depending on (can be a string, number, boolean, etc.)
23
- * `default`: the default value if the `dependsOn` value is not found
@@ -1,35 +0,0 @@
1
- // TODO: implement a *synchronous* profile chooser that executes the correct launch command
2
-
3
- // Import libs
4
- import path from 'path';
5
- import fs from 'fs';
6
-
7
- // Import helpers
8
- import print from './helpers/print';
9
- import showChooser from './helpers/showChooser';
10
-
11
- // Get the project directory
12
- const pwd = path.join(process.env.PWD || process.env.CWD || __dirname, '../..');
13
- // NOTE: this is a dependency of the main project, so the actual project
14
- // directory is up two levels (outside this folder, then outside node_modules)
15
- console.log('Project directory:', pwd);
16
-
17
- // TODO: explore the file tree to figure out which profiles exist
18
- // (Build a chooser based on what you find)
19
- // Maybe: /cypress/profiles/[Name].Profile.ts
20
-
21
- print.title('Here\'s a title');
22
-
23
- console.log('Let us do the thing.');
24
- print.enterToContinue();
25
-
26
- const choice = showChooser({
27
- question: 'Choose an option:',
28
- options: [
29
- { tag: 'A', description: 'First option' },
30
- { tag: 'B', description: 'Second option' },
31
- { tag: 'C', description: 'Third option' },
32
- ],
33
- });
34
-
35
- console.log('You chose:', choice);
@@ -1,155 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- /**
4
- * Get the left buffer for a centered message
5
- * @author Gabe Abrams
6
- * @param message message to print
7
- * @param padding amount of padding to add
8
- * @returns number of chars in the buffer
9
- */
10
- const leftBuffer = (message: string, padding: number): number => {
11
- return (Math.floor(process.stdout.columns / 2) - padding - Math.ceil(message.length / 2));
12
- };
13
-
14
- /**
15
- * Get the right buffer for a centered message
16
- * @author Gabe Abrams
17
- * @param message message to print
18
- * @param padding amount of padding to add
19
- * @returns number of chars in the buffer
20
- */
21
- const rightBuffer = (message: string, padding: number): number => {
22
- return (Math.ceil(process.stdout.columns / 2) - padding - Math.floor(message.length / 2));
23
- };
24
-
25
- /**
26
- * Surround text with a border and spaces
27
- * @author Gabe Abrams
28
- * @param str text to print
29
- * @param border single character to use as a border
30
- * @returns text to print
31
- */
32
- const surroundWithBuffer = (str: string, border: string): string => {
33
- return (
34
- border
35
- + ' '.repeat(leftBuffer(str, border.length))
36
- + str
37
- + ' '.repeat(rightBuffer(str, border.length))
38
- + border
39
- );
40
- };
41
-
42
- /**
43
- * Surround text with a character as the buffer
44
- * @author Gabe Abrams
45
- * @param str text to print
46
- * @param char character to place as the buffer
47
- * @returns text to print
48
- */
49
- const surroundWithChars = (str: string, char: string): string => {
50
- if (str.length > process.stdout.columns) {
51
- return str;
52
- }
53
- if (str.length === process.stdout.columns - 1) {
54
- return char + str;
55
- }
56
- if (str.length === process.stdout.columns - 2) {
57
- return char + str + char;
58
- }
59
- return (
60
- char.repeat(leftBuffer(str, 1))
61
- + ' '
62
- + str
63
- + ' '
64
- + char.repeat(rightBuffer(str, 1))
65
- );
66
- };
67
-
68
- // Prompt instance
69
- let cachedPrompt: any;
70
-
71
- const print = {
72
- /**
73
- * Print a title
74
- * @author Gabe Abrams
75
- * @param str text to print
76
- */
77
- title: (str: string) => {
78
- if (str.length > process.stdout.columns) {
79
- return console.log(str);
80
- }
81
- console.log('\u2554' + '\u2550'.repeat(process.stdout.columns - 2) + '\u2557');
82
- console.log(surroundWithBuffer(str, '\u2551'));
83
- console.log('\u255A' + '\u2550'.repeat(process.stdout.columns - 2) + '\u255D');
84
- },
85
- /**
86
- * Print a sub title (subheading)
87
- * @author Gabe Abrams
88
- * @param str text to print
89
- */
90
- subtitle: (str: string) => {
91
- if (str.length > process.stdout.columns) {
92
- return console.log(str);
93
- }
94
- console.log(surroundWithChars(str, '\u257C'));
95
- },
96
- /**
97
- * Print centered text
98
- * @author Gabe Abrams
99
- * @param str text to print
100
- */
101
- centered: (str: string) => {
102
- const lines = [];
103
- let index = 0;
104
- while (index < str.length) {
105
- lines.push(str.substring(index, Math.min(index + process.stdout.columns, str.length)));
106
- index += process.stdout.columns;
107
- }
108
- lines.forEach((line, lineIndex) => {
109
- if (lineIndex !== lines.length - 1) {
110
- // No need to center: fills whole line
111
- console.log(line);
112
- } else {
113
- // This line needs to be centered
114
- console.log(surroundWithChars(line, ' '));
115
- }
116
- });
117
- },
118
- /**
119
- * Print a fatal error message
120
- * @author Gabe Abrams
121
- * @param err error message
122
- */
123
- fatalError: (err: string) => {
124
- console.log('\n');
125
- const errLine1 = err.substring(0, process.stdout.columns - 6);
126
- const errLine2 = err.substring(process.stdout.columns - 6);
127
- console.log('\u2554' + '\u2550'.repeat(3) + '\u2557 ');
128
- console.log(`\u2551 ! \u2551 ${errLine1}`);
129
- console.log('\u255A' + '\u2550'.repeat(3) + '\u255D ' + errLine2);
130
- process.exit(0);
131
- },
132
- /**
133
- * Save a copy of the prompt instance
134
- * @author Gabe Abrams
135
- * @param promptInstance instance of prompt-sync
136
- */
137
- savePrompt: (promptInstance: any) => {
138
- cachedPrompt = promptInstance;
139
- },
140
- /**
141
- * Ask the user to press enter before continuing
142
- * @author Gabe Abrams
143
- */
144
- enterToContinue: () => {
145
- const res = cachedPrompt(
146
- surroundWithChars('enter to continue, ctrl+c to quit', '\u257C'),
147
- true,
148
- );
149
- if (res === null) {
150
- process.exit(0);
151
- }
152
- },
153
- };
154
-
155
- export default print;
@@ -1,23 +0,0 @@
1
- import initPrompt from 'prompt-sync';
2
- import print from './print';
3
-
4
- const promptSync = initPrompt();
5
-
6
- /**
7
- * Ask the user a question
8
- * @param title title of the question
9
- * @param notRequired true if question is not required
10
- * @returns response
11
- */
12
- const prompt = (title: string, notRequired?: boolean): string => {
13
- const val = promptSync(title);
14
- if (val === null || (!notRequired && !val)) {
15
- process.exit(0);
16
- }
17
- return val;
18
- };
19
-
20
- // Save the prompt for use later
21
- print.savePrompt(prompt);
22
-
23
- export default prompt;