Use Flow to typecheck JavaScript code.
Change-Id: I9c0c9b5aa74d592a04eb6533e64669f1896fb7cd
diff --git a/build.gradle b/build.gradle
index 6274531..773eb8e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -129,8 +129,20 @@
commandLine "yarn", "run", "snowpack", "--optimize"
}
+task flow(type:Exec) {
+ def resourceDir = "src/main/resources/META-INF/resources"
+
+ onlyIf { !project.hasProperty('skipWeb') }
+
+ dependsOn snowpack
+
+ workingDir resourceDir
+ commandLine "yarn", "run", "flow", "--color=always"
+}
+
task compileWeb {
dependsOn snowpack
+ dependsOn flow
doLast {}
}
diff --git a/src/main/resources/META-INF/resources/.flowconfig b/src/main/resources/META-INF/resources/.flowconfig
new file mode 100644
index 0000000..fe59993
--- /dev/null
+++ b/src/main/resources/META-INF/resources/.flowconfig
@@ -0,0 +1,8 @@
+[libs]
+
+[ignore]
+<PROJECT_ROOT>/node_modules/.*
+
+[options]
+emoji=true
+module.system.node.resolve_dirname=node_modules
diff --git a/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js b/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js
index 012a314..41892c1 100644
--- a/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js
+++ b/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js
@@ -1,3 +1,5 @@
+// @flow
+
import ProgressSpinner from "../web_modules/elix/define/ProgressSpinner.js";
const template = document.createElement('template');
@@ -33,18 +35,27 @@
</form>`;
export class MlkBookmarkSubmissionForm extends HTMLElement {
+ /*::
+ descriptionInput: HTMLTextAreaElement;
+ titleInput: HTMLInputElement;
+ uriInput: HTMLInputElement;
+ uriSpinner: ProgressSpinner;
+ */
+
constructor() {
super();
- this.onUriBlur = this.onUriBlur.bind(this);
-
let shadow = this.attachShadow({mode: "open"});
- this.shadowRoot.appendChild(template.content.cloneNode(true));
+ shadow.appendChild(template.content.cloneNode(true));
- this.descriptionInput = shadow.getElementById('description-input');
- this.titleInput = shadow.getElementById('title-input');
- this.uriInput = shadow.getElementById('uri-input');
- this.uriSpinner = shadow.getElementById('uri-spinner');
+ this.descriptionInput =
+ this.cast(shadow.getElementById('description-input'));
+ this.titleInput =
+ this.cast(shadow.getElementById('title-input'));
+ this.uriInput =
+ this.cast(shadow.getElementById('uri-input'));
+ this.uriSpinner =
+ this.cast(shadow.getElementById('uri-spinner'));
}
static get observedAttributes() {
@@ -52,21 +63,20 @@
}
connectedCallback () {
- this.uriInput.addEventListener('blur', this.onUriBlur);
+ this.uriInput.addEventListener('blur', this.onUriBlur.bind(this));
this.uriInput.value = this.uri || "";
- this.titleInput.value = this.title || "";
+ this.titleInput.value = this.titleText || "";
this.descriptionInput.innerText = this.description || "";
}
- attributeChangedCallback(name, oldValue, newValue) {
- this.render();
+ attributeChangedCallback(name /*:string*/, oldValue /*:string*/, newValue /*:string*/) {
}
get uri() {
return this.getAttribute("uri");
}
- get title() {
+ get titleText() {
return this.getAttribute("title");
}
@@ -93,8 +103,8 @@
this.uriSpinner.hidden = false;
this.uriSpinner.playing = true;
let searchParams = new URLSearchParams({'uri': this.uriInput.value});
- console.log(`/bookmarks/page-info?${searchParams}`);
- let fetchUrl = new URL(`/bookmarks/page-info?${searchParams}`, document.URL);
+ console.log(`/bookmarks/page-info?${searchParams.toString()}`);
+ let fetchUrl = new URL(`/bookmarks/page-info?${searchParams.toString()}`, document.URL);
let r = await fetch(fetchUrl);
this.uriSpinner.hidden = true;
this.uriSpinner.playing = false;
@@ -106,6 +116,16 @@
let pageInfo = await r.json();
this.titleInput.value = pageInfo.title;
}
+
+ cast/*:: <T>*/(x /*: ?Object*/) /*: T*/ {
+ if (x === null || x === undefined) {
+ throw "unexpected null or undefined";
+ } else {
+ /*:: (x: T); */
+ return x;
+ }
+ }
+
}
customElements.define("mlk-bookmark-submission-form", MlkBookmarkSubmissionForm);
diff --git a/src/main/resources/META-INF/resources/package.json b/src/main/resources/META-INF/resources/package.json
index d0657d4..dc8cdeb 100644
--- a/src/main/resources/META-INF/resources/package.json
+++ b/src/main/resources/META-INF/resources/package.json
@@ -13,6 +13,7 @@
"sanitize.css": "^11.0.0"
},
"devDependencies": {
+ "flow-bin": "^0.118.0",
"snowpack": "^1.1.0"
},
"snowpack": {
diff --git a/src/main/resources/META-INF/resources/yarn.lock b/src/main/resources/META-INF/resources/yarn.lock
index 2b69a44..1a2a5a1 100644
--- a/src/main/resources/META-INF/resources/yarn.lock
+++ b/src/main/resources/META-INF/resources/yarn.lock
@@ -1051,6 +1051,11 @@
resolved "https://registry.yarnpkg.com/find-package-json/-/find-package-json-1.2.0.tgz#4057d1b943f82d8445fe52dc9cf456f6b8b58083"
integrity sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==
+flow-bin@^0.118.0:
+ version "0.118.0"
+ resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.118.0.tgz#fb706364a58c682d67a2ca7df39396467dc397d1"
+ integrity sha512-jlbUu0XkbpXeXhan5xyTqVK1jmEKNxE8hpzznI3TThHTr76GiFwK0iRzhDo4KNy+S9h/KxHaqVhTP86vA6wHCg==
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"