Skip to content

Commit

Permalink
chore (tsc): type check and linter
Browse files Browse the repository at this point in the history
  • Loading branch information
mickael-kerjean committed Oct 19, 2023
1 parent cdfc614 commit 5a09186
Show file tree
Hide file tree
Showing 22 changed files with 124 additions and 68 deletions.
4 changes: 2 additions & 2 deletions public/boot/ctrl_boot_frontoffice.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ function setup_translation() {
selectedLanguage = "zh_tw";
break;
default:
const userLanguage = window.navigator.language.split("-")[0];
const userLanguage = window.navigator.language.split("-")[0] || "en";
const idx = [
"az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "et",
"eu", "fi", "fr", "gl", "hr", "hu", "id", "is", "it", "ja",
"ka", "ko", "lt", "lv", "mn", "nb", "nl", "pl", "pt", "ro",
"ru", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh"
].indexOf(window.navigator.language.split("-")[0]);
].indexOf(window.navigator.language.split("-")[0] || "");
if (idx !== -1) {
selectedLanguage = userLanguage;
}
Expand Down
2 changes: 1 addition & 1 deletion public/components/breadcrumb.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const css = await CSS(import.meta.url, "breadcrumb.css");
class ComponentBreadcrumb extends HTMLDivElement {
constructor() {
super();
if (new window.URL(location.href).searchParams.get("nav") === "false") return null;
if (new window.URL(location.href).searchParams.get("nav") === "false") return;

const htmlLogout = isRunningFromAnIframe
? ""
Expand Down
39 changes: 26 additions & 13 deletions public/components/form.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createElement } from "../lib/skeleton/index.js";
import { gid } from "../lib/random.js";
import { ApplicationError } from "../lib/error.js";

import "./icon.js";

Expand Down Expand Up @@ -76,7 +77,8 @@ export function $renderInput(options = {}) {
class="component_input"
/>
`);
$input.setAttribute("value", value || "");
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
attrs.map((setAttribute) => setAttribute($input));

if (!datalist) return $input;
Expand All @@ -94,17 +96,19 @@ export function $renderInput(options = {}) {
$datalist.appendChild(new Option(value));
});
if (!props.multi) return $wrapper;
// @ts-ignore
$input.refresh = () => {
const _datalist = $input.getAttribute("datalist").split(",");
const _datalist = $input?.getAttribute("datalist")?.split(",");
$datalist.innerHTML = "";
multicomplete($input.getAttribute("value"), _datalist).forEach((value) => {
$datalist.appendChild(new Option(value));
});
};
$input.oninput = (e) => {
$input.oninput = () => {
for (const $option of $datalist.children) {
$option.remove();
}
// @ts-ignore
$input.refresh();
};
return $wrapper;
Expand All @@ -130,7 +134,8 @@ export function $renderInput(options = {}) {
class="component_input"
/>
`);
$input.setAttribute("value", value);
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
attrs.map((setAttribute) => setAttribute($input));
return $input;
}
Expand All @@ -145,14 +150,16 @@ export function $renderInput(options = {}) {
</div>
`);
const $input = $div.querySelector("input");
$input.value = value;
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
attrs.map((setAttribute) => setAttribute($input));

const $icon = $div.querySelector("component-icon");
if ($icon instanceof window.HTMLElement) {
$icon.onclick = function(e) {
if (!(e.target instanceof window.HTMLElement)) return;
const $input = e.target.parentElement.previousElementSibling;
const $input = e.target?.parentElement?.previousElementSibling;
if (!$input) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
if ($input.getAttribute("type") === "password") $input.setAttribute("type", "text");
else $input.setAttribute("type", "password");
};
Expand All @@ -166,7 +173,8 @@ export function $renderInput(options = {}) {
rows="8"
></textarea>
`);
$textarea.setAttribute("value", value);
if (!($textarea instanceof window.HTMLTextAreaElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $textarea.value = value;
attrs.map((setAttribute) => setAttribute($textarea));
return $textarea;
}
Expand All @@ -178,15 +186,17 @@ export function $renderInput(options = {}) {
readonly
/>
`);
$input.setAttribute("value", value);
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
attrs.map((setAttribute) => setAttribute($input));
return $input;
}
case "hidden": {
const $input = createElement(`
<input type="hidden" />
`);
$input.setAttribute("value", value);
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
$input.setAttribute("name", path.join("."));
return $input;
}
Expand All @@ -208,7 +218,8 @@ export function $renderInput(options = {}) {
const $select = createElement(`
<select class="component_select"></select>
`);
$select.setAttribute("value", value || props.default);
if (!($select instanceof window.HTMLSelectElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $select.value = value || props.default;
attrs.map((setAttribute) => setAttribute($select));
(options || []).forEach((name) => {
const $option = createElement(`
Expand All @@ -230,7 +241,8 @@ export function $renderInput(options = {}) {
class="component_input"
/>
`);
$input.setAttribute("value", value);
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
attrs.map((setAttribute) => setAttribute($input));
return $input;
}
Expand All @@ -241,7 +253,8 @@ export function $renderInput(options = {}) {
class="component_input"
/>
`);
$input.setAttribute("value", value);
if (!($input instanceof window.HTMLInputElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing input");
else if (value) $input.value = value;
attrs.map((setAttribute) => setAttribute($input));
return $input;
}
Expand Down Expand Up @@ -285,7 +298,7 @@ export function format(name) {
if (word.length < 1) {
return word;
}
return word[0].toUpperCase() + word.substring(1);
return (word[0] || "").toUpperCase() + word.substring(1);
})
.join(" ");
};
Expand Down
2 changes: 1 addition & 1 deletion public/components/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Loader extends window.HTMLElement {
this.innerHTML = this.render({
inline: this.hasAttribute("inlined"),
});
}, parseInt(this.getAttribute("delay")) || 0);
}, parseInt(this.getAttribute("delay") || "0"));
}

disconnectedCallback() {
Expand Down
13 changes: 10 additions & 3 deletions public/components/notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class NotificationComponent extends window.HTMLElement {
this.buffer.push({ message, type });
if (this.buffer.length !== 1) {
const $close = this.querySelector(".close");
if ($close && typeof $close.onclick === "function") $close.onclick();
if (!($close instanceof window.HTMLElement) || !$close.onclick) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: notification close button missing");
$close.onclick(new window.MouseEvent("mousedown"));
return;
}
await this.run();
Expand All @@ -42,8 +43,14 @@ class NotificationComponent extends window.HTMLElement {
});
const ids = [];
await Promise.race([
new Promise((done) => ids.push(window.setTimeout(done, this.buffer.length === 1 ? 8000 : 800))),
new Promise((done) => ids.push(window.setTimeout(() => $notification.querySelector(".close").onclick = done, 1000))),
new Promise((done) => ids.push(window.setTimeout(() => {
done(new window.MouseEvent("mousedown"));
}, this.buffer.length === 1 ? 8000 : 800))),
new Promise((done) => ids.push(window.setTimeout(() => {
const $close = $notification.querySelector(".close");
if (!($close instanceof window.HTMLElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: notification close button missing");
$close.onclick = done;
}, 1000))),
]);
ids.forEach((id) => window.clearTimeout(id));
await animate($notification, {
Expand Down
2 changes: 1 addition & 1 deletion public/helpers/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function loadSingleCSS(baseURL, filename) {
cache: "force-cache",
});
if (res.status !== 200) return `/* ERROR: ${res.status} */`;
else if (!res.headers.get("Content-Type").startsWith("text/css")) return `/* ERROR: wrong type, got "${res.headers.get("Content-Type")}"*/`;
else if (!res.headers.get("Content-Type")?.startsWith("text/css")) `/* ERROR: wrong type, got "${res.headers?.get("Content-Type")}"*/`;
return await res.text();
}

Expand Down
9 changes: 7 additions & 2 deletions public/lib/form.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createElement } from "./skeleton/index.js";
import { ApplicationError } from "./error.js";
import { animate } from "./animate.js";

export function mutateForm(formSpec, formState) {
Expand All @@ -7,8 +8,12 @@ export function mutateForm(formSpec, formState) {
const keys = inputName.split(".");

let ptr = formSpec;
while (keys.length > 1) ptr = ptr[keys.shift()];
const key = keys.shift();
while (keys.length > 1) {
let k = keys.shift();
if (!k) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing key");
ptr = ptr[k];
}
const key = keys.shift() || "";
if (ptr && ptr[key]) ptr[key].value = (value === "" ? null : value);
});
return formSpec;
Expand Down
35 changes: 17 additions & 18 deletions public/lib/locales.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
export default function t(str = "", replacementString, requestedKey) {
return str;
// const calculatedKey = str.toUpperCase()
// .replace(/ /g, "_")
// .replace(/[^a-zA-Z0-9\-\_\*\{\}\?]/g, "")
// .replace(/\_+$/, "");
// const value = requestedKey === undefined ?
// window.LNG && window.LNG[calculatedKey] :
// window.LNG && window.LNG[requestedKey];
// return reformat(
// value || str || "",
// str,
// ).replace("{{VALUE}}", replacementString);
const calculatedKey = str.toUpperCase()
.replace(/ /g, "_")
.replace(/[^a-zA-Z0-9\-\_\*\{\}\?]/g, "")
.replace(/\_+$/, "");
const value = requestedKey === undefined ?
window.LNG && window.LNG[calculatedKey] :
window.LNG && window.LNG[requestedKey];
return reformat(
value || str || "",
str,
).replace("{{VALUE}}", replacementString);
}

// function reformat(translated, initial) {
// if (initial[0] && initial[0].toLowerCase() === initial[0]) {
// return translated || "";
// }
// return (translated[0] && translated[0].toUpperCase() + translated.substring(1)) || "";
// }
function reformat(translated, initial) {
if (initial[0] && initial[0].toLowerCase() === initial[0]) {
return translated || "";
}
return (translated[0] && translated[0].toUpperCase() + translated.substring(1)) || "";
}
2 changes: 1 addition & 1 deletion public/lib/skeleton/router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe("router", () => {
// then
expect(fn).toBeCalled();
});
xit("trigger a page change when clicking on a link with [data-link] attribute", () => {
it("trigger a page change when clicking on a link with [data-link] attribute", () => {
// given
const fn = jest.fn();
const $link = createElement("<a href=\"/something\" data-link></a>");
Expand Down
1 change: 1 addition & 0 deletions public/lib/vendor/bcrypt.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-nocheck
// code was adapted from https://github.com/dcodeIO/bcrypt.js, meaning:
// - we took the code from a CDN https://cdnjs.cloudflare.com/ajax/libs/bcryptjs/2.2.0/bcrypt.js
// - remove the amd,commonJS stuff on the top of the file
Expand Down
6 changes: 4 additions & 2 deletions public/pages/adminpage/component_box-item.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ApplicationError } from "../../lib/error.js";

class BoxItem extends window.HTMLDivElement {
constructor() {
super();
Expand All @@ -11,12 +13,11 @@ class BoxItem extends window.HTMLDivElement {
attributeChangedCallback() {
this.innerHTML = this.render({
label: this.getAttribute("data-label"),
selected: false,
});
this.classList.add("box-item", "pointer", "no-select");
}

render({ label, selected }) {
render({ label }) {
return `
<div>
<strong>${label}</strong>
Expand All @@ -30,6 +31,7 @@ class BoxItem extends window.HTMLDivElement {
toggleSelection(opt = {}) {
const { tmpl, isSelected = !this.classList.contains("active") } = opt;
const $icon = this.querySelector(".icon");
if (!$icon) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: no icon");
if (isSelected) {
this.classList.add("active");
if (tmpl) $icon.innerHTML = tmpl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createElement } from "../../lib/skeleton/index.js";
import rxjs, { effect, applyMutation, applyMutations, onClick } from "../../lib/rx.js";
import { createForm, mutateForm } from "../../lib/form.js";
import { qs, qsa } from "../../lib/dom.js";
import { ApplicationError } from "../../lib/error.js";
import { formTmpl } from "../../components/form.js";
import { generateSkeleton } from "../../components/skeleton.js";

Expand Down Expand Up @@ -77,7 +78,10 @@ export default async function(render) {
})),
rxjs.map((idpState) => [availableSpecs, idpState]),
)),
rxjs.concatMap(async([availableSpecs, idpState = {}]) => {
rxjs.concatMap(async([
availableSpecs,
idpState = { type: null, params: null },
]) => {
const { type, params } = idpState;
const idps = [];
for (const key in availableSpecs) {
Expand Down Expand Up @@ -167,7 +171,9 @@ export default async function(render) {
rxjs.map((connections) => connections.map(({ label }) => label)),
rxjs.tap((datalist) => {
const $input = $page.querySelector("[name=\"attribute_mapping.related_backend\"]");
if (!$input) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: missing related backend");
$input.setAttribute("datalist", datalist.join(","));
// @ts-ignore
$input.refresh();
}),
));
Expand Down Expand Up @@ -238,6 +244,7 @@ export default async function(render) {
renderLeaf: () => createElement("<label></label>"),
}))),
rxjs.tap(($node) => {
/** @type { Element | undefined} */
let $relatedBackendField;
$page.querySelectorAll("[data-bind=\"attribute-mapping\"] fieldset").forEach(($el, i) => {
if (i === 0) $relatedBackendField = $el;
Expand Down
18 changes: 12 additions & 6 deletions public/pages/adminpage/ctrl_backend_state.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import rxjs from "../../lib/rx.js";
import { qs } from "../../lib/dom.js";
import { ApplicationError } from "../../lib/error.js";
import { get as getConfig } from "../../model/config.js";
import { get as getAdminConfig } from "./model_config.js";
import { formObjToJSON$ } from "./helper_form.js";
Expand Down Expand Up @@ -92,15 +93,18 @@ export function getState() {
};
if (!authType) return config;

let formValues = [...new FormData(document.querySelector("[data-bind=\"idp\"]"))];
const $formIDP = document.querySelector("[data-bind=\"idp\"]")
if (!($formIDP instanceof window.HTMLFormElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: idp isn't a form");
let formValues = [...new FormData($formIDP)];
config.middleware.identity_provider = {
type: authType,
params: JSON.stringify(
formValues
.filter(([key, value]) => key.startsWith(`${authType}.`)) // remove elements that aren't in scope
.filter(([key]) => key.startsWith(`${authType}.`)) // remove elements that aren't in scope
.map(([key, value]) => [key.replace(new RegExp(`^${authType}\.`), ""), value]) // format the relevant keys
.reduce((acc, [key, value]) => { // transform onto something ready to be saved
if (key === "type") return acc;
else if (typeof key !== "string") return acc;
return {
...acc,
[key]: value,
Expand All @@ -109,14 +113,16 @@ export function getState() {
),
};

formValues = [...new FormData(document.querySelector("[data-bind=\"attribute-mapping\"]"))];
const $formAM = document.querySelector("[data-bind=\"attribute-mapping\"]");
if (!($formAM instanceof window.HTMLFormElement)) throw new ApplicationError("INTERNAL_ERROR", "assumption failed: attribute mapping isn't a form");
formValues = [...new FormData($formAM)];
config.middleware.attribute_mapping = {
related_backend: formValues.shift()[1],
related_backend: (formValues.shift() || [])[1],
params: JSON.stringify(formValues.reduce((acc, [key, value]) => {
const k = key.split(".");
if (k.length !== 2) return acc;
if (!acc[k[0]]) acc[k[0]] = {};
if (value !== "") acc[k[0]][k[1]] = value;
if (!acc[`${k[0]}`]) acc[`${k[0]}`] = {};
if (value !== "") acc[`${k[0]}`][`${k[1]}`] = value;
return acc;
}, {})),
};
Expand Down
Loading

0 comments on commit 5a09186

Please sign in to comment.