summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoshiya Hinosawa <stibium121@gmail.com>2020-10-13 22:31:59 +0900
committerGitHub <noreply@github.com>2020-10-13 15:31:59 +0200
commit0dcaea72aeec52a566764b41b10d8fd1854d6fa4 (patch)
tree1c1bfe56b3ac846e83fae48ed5546116d3aea05d
parent0bd3cea0ff6d2d4840c0df2938b5ae5c5d7cc4bd (diff)
feat: add alert, confirm, and prompt (#7507)
This commit adds "alert", "confirm" and "prompt" functions from web standards.
-rw-r--r--cli/dts/lib.deno.window.d.ts29
-rw-r--r--cli/rt/41_prompt.js66
-rw-r--r--cli/rt/99_main.js4
-rw-r--r--cli/tests/066_prompt.ts17
-rw-r--r--cli/tests/066_prompt.ts.out8
-rw-r--r--cli/tests/integration_tests.rs11
6 files changed, 135 insertions, 0 deletions
diff --git a/cli/dts/lib.deno.window.d.ts b/cli/dts/lib.deno.window.d.ts
index 03341636f..541eee370 100644
--- a/cli/dts/lib.deno.window.d.ts
+++ b/cli/dts/lib.deno.window.d.ts
@@ -15,6 +15,9 @@ declare class Window extends EventTarget {
onunload: ((this: Window, ev: Event) => any) | null;
close: () => void;
readonly closed: boolean;
+ alert: (message?: string) => void;
+ confirm: (message?: string) => boolean;
+ prompt: (message?: string, defaultValue?: string) => string | null;
Deno: typeof Deno;
}
@@ -23,4 +26,30 @@ declare var self: Window & typeof globalThis;
declare var onload: ((this: Window, ev: Event) => any) | null;
declare var onunload: ((this: Window, ev: Event) => any) | null;
+/**
+ * Shows the given message and waits for the enter key pressed.
+ * If the stdin is not interactive, it does nothing.
+ * @param message
+ */
+declare function alert(message?: string): void;
+
+/**
+ * Shows the given message and waits for the answer. Returns the user's answer as boolean.
+ * Only `y` and `Y` are considered as true.
+ * If the stdin is not interactive, it returns false.
+ * @param message
+ */
+declare function confirm(message?: string): boolean;
+
+/**
+ * Shows the given message and waits for the user's input. Returns the user's input as string.
+ * If the default value is given and the user inputs the empty string, then it returns the given
+ * default value.
+ * If the default value is not given and the user inputs the empty string, it returns null.
+ * If the stdin is not interactive, it returns null.
+ * @param message
+ * @param defaultValue
+ */
+declare function prompt(message?: string, defaultValue?: string): string | null;
+
/* eslint-enable @typescript-eslint/no-explicit-any */
diff --git a/cli/rt/41_prompt.js b/cli/rt/41_prompt.js
new file mode 100644
index 000000000..5a588def1
--- /dev/null
+++ b/cli/rt/41_prompt.js
@@ -0,0 +1,66 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+((window) => {
+ const { stdin, stdout } = window.__bootstrap.files;
+ const { isatty } = window.__bootstrap.tty;
+ const LF = "\n".charCodeAt(0);
+ const encoder = new TextEncoder();
+ const decoder = new TextDecoder();
+
+ function alert(message = "Alert") {
+ if (!isatty(stdin.rid)) {
+ return;
+ }
+
+ stdout.writeSync(encoder.encode(`${message} [Enter] `));
+
+ readLineFromStdinSync();
+ }
+
+ function confirm(message = "Confirm") {
+ if (!isatty(stdin.rid)) {
+ return false;
+ }
+
+ stdout.writeSync(encoder.encode(`${message} [y/N] `));
+
+ const answer = readLineFromStdinSync();
+
+ return answer === "Y" || answer === "y";
+ }
+
+ function prompt(message = "Prompt", defaultValue) {
+ defaultValue ??= null;
+
+ if (!isatty(stdin.rid)) {
+ return null;
+ }
+
+ stdout.writeSync(encoder.encode(`${message} `));
+
+ if (defaultValue) {
+ stdout.writeSync(encoder.encode(`[${defaultValue}] `));
+ }
+
+ return readLineFromStdinSync() || defaultValue;
+ }
+
+ function readLineFromStdinSync() {
+ const c = new Uint8Array(1);
+ const buf = [];
+
+ while (true) {
+ const n = stdin.readSync(c);
+ if (n === 0 || c[0] === LF) {
+ break;
+ }
+ buf.push(c[0]);
+ }
+ return decoder.decode(new Uint8Array(buf));
+ }
+
+ window.__bootstrap.prompt = {
+ alert,
+ confirm,
+ prompt,
+ };
+})(this);
diff --git a/cli/rt/99_main.js b/cli/rt/99_main.js
index d8c34bcb3..e33264726 100644
--- a/cli/rt/99_main.js
+++ b/cli/rt/99_main.js
@@ -27,6 +27,7 @@ delete Object.prototype.__proto__;
const fileReader = window.__bootstrap.fileReader;
const webSocket = window.__bootstrap.webSocket;
const fetch = window.__bootstrap.fetch;
+ const prompt = window.__bootstrap.prompt;
const denoNs = window.__bootstrap.denoNs;
const denoNsUnstable = window.__bootstrap.denoNsUnstable;
const errors = window.__bootstrap.errors.errors;
@@ -285,6 +286,9 @@ delete Object.prototype.__proto__;
onunload: util.writable(null),
close: util.writable(windowClose),
closed: util.getterOnly(() => windowIsClosing),
+ alert: util.writable(prompt.alert),
+ confirm: util.writable(prompt.confirm),
+ prompt: util.writable(prompt.prompt),
};
const workerRuntimeGlobalProperties = {
diff --git a/cli/tests/066_prompt.ts b/cli/tests/066_prompt.ts
new file mode 100644
index 000000000..1c4a11f98
--- /dev/null
+++ b/cli/tests/066_prompt.ts
@@ -0,0 +1,17 @@
+const name0 = prompt("What is your name?", "Jane Doe"); // Answer John Doe
+console.log(`Your name is ${name0}.`);
+const name1 = prompt("What is your name?", "Jane Doe"); // Answer with default
+console.log(`Your name is ${name1}.`);
+const input = prompt(); // Answer foo
+console.log(`Your input is ${input}.`);
+const answer0 = confirm("Question 0"); // Answer y
+console.log(`Your answer is ${answer0}`);
+const answer1 = confirm("Question 1"); // Answer n
+console.log(`Your answer is ${answer1}`);
+const answer2 = confirm("Question 2"); // Answer with yes (returns false)
+console.log(`Your answer is ${answer2}`);
+const answer3 = confirm(); // Answer with default
+console.log(`Your answer is ${answer3}`);
+alert("Hi");
+alert();
+console.log("The end of test");
diff --git a/cli/tests/066_prompt.ts.out b/cli/tests/066_prompt.ts.out
new file mode 100644
index 000000000..88d73f34f
--- /dev/null
+++ b/cli/tests/066_prompt.ts.out
@@ -0,0 +1,8 @@
+[WILDCARD]What is your name? [Jane Doe] Your name is John Doe.
+What is your name? [Jane Doe] Your name is Jane Doe.
+Prompt Your input is foo.
+Question 0 [y/N] Your answer is true
+Question 1 [y/N] Your answer is false
+Question 2 [y/N] Your answer is false
+Confirm [y/N] Your answer is false
+Hi [Enter] Alert [Enter] The end of test
diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs
index 1a5e48ada..90dc5a4a8 100644
--- a/cli/tests/integration_tests.rs
+++ b/cli/tests/integration_tests.rs
@@ -1917,6 +1917,17 @@ itest!(_065_import_map_info {
output: "065_import_map_info.out",
});
+#[cfg(unix)]
+#[test]
+fn _066_prompt() {
+ let args = "run --unstable 066_prompt.ts";
+ let output = "066_prompt.ts.out";
+ // These are answers to prompt, confirm, and alert calls.
+ let input = b"John Doe\n\nfoo\nY\nN\nyes\n\n\n\n";
+
+ util::test_pty(args, output, input);
+}
+
itest!(js_import_detect {
args: "run --quiet --reload js_import_detect.ts",
output: "js_import_detect.ts.out",