From eff4bce96a482f70e4ac9f4e78a8aa20c1a2269d Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 16:21:09 +0200 Subject: [PATCH 01/18] chore(typechecking): add typechecking on fake-string.js --- src/lib/fake-strings.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/fake-strings.js b/src/lib/fake-strings.js index d03fb486c..d05757a76 100644 --- a/src/lib/fake-strings.js +++ b/src/lib/fake-strings.js @@ -2,7 +2,12 @@ const FAKE_STRING_BASE = '??? ??????????? ???? ?????? ??? ????????????? ????????? ?? ??????? ?? ????? ????????????? ?? ?????? ??? ?? ??????? ?? ????????? ?? ?????????? ?? ??????????? ????? ?????????? ?? ???? ???????????? ???? ????? ????????????????'; -// Create a fake string of `charCount` characters -export function fakeString(chatCount) { - return FAKE_STRING_BASE.substr(0, chatCount); +/** + * Creates a fake string of `charCount` characters + * + * @param {number} charCount + * @return {string} + */ +export function fakeString(charCount) { + return FAKE_STRING_BASE.substring(0, charCount); } From 9743d186a0a732d4189454b1feb92ffe58c0ee28 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 16:24:16 +0200 Subject: [PATCH 02/18] chore(typechecking): add typechecking on animate.js --- .../cc-tile-instances/cc-tile-instances.js | 14 ++++++++++++-- src/lib/animate.js | 15 +++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/components/cc-tile-instances/cc-tile-instances.js b/src/components/cc-tile-instances/cc-tile-instances.js index ce74df152..45caa9857 100644 --- a/src/components/cc-tile-instances/cc-tile-instances.js +++ b/src/components/cc-tile-instances/cc-tile-instances.js @@ -93,7 +93,12 @@ export class CcTileInstances extends LitElement { if (this._lastRunningCount !== runningInstancesCount) { this.updateComplete.then(() => { // This is not supported in Safari yet, but it's purely decorative so let's keep it like that - animate(this.shadowRoot, '.instances[data-type=running] .count-bubble', ...QUICK_SHRINK); + animate( + this.shadowRoot, + '.instances[data-type=running] .count-bubble', + QUICK_SHRINK.keyframes, + QUICK_SHRINK.options, + ); this._lastRunningCount = runningInstancesCount; }); } @@ -101,7 +106,12 @@ export class CcTileInstances extends LitElement { if (this._lastDeployingCount !== deployingInstancesCount) { this.updateComplete.then(() => { // This is not supported in Safari yet, but it's purely decorative so let's keep it like that - animate(this.shadowRoot, '.instances[data-type=deploying] .count-bubble', ...QUICK_SHRINK); + animate( + this.shadowRoot, + '.instances[data-type=deploying] .count-bubble', + QUICK_SHRINK.keyframes, + QUICK_SHRINK.options, + ); this._lastDeployingCount = deployingInstancesCount; }); } diff --git a/src/lib/animate.js b/src/lib/animate.js index 11f363496..e2e4ba699 100644 --- a/src/lib/animate.js +++ b/src/lib/animate.js @@ -1,11 +1,18 @@ +/** + * + * @param {ShadowRoot} shadowRoot + * @param {string} selector + * @param {Array | PropertyIndexedKeyframes} keyframes + * @param {number | KeyframeAnimationOptions} options + */ export function animate(shadowRoot, selector, keyframes, options) { Array.from(shadowRoot.querySelectorAll(selector)).forEach((element) => element.animate(keyframes, options)); } -export const QUICK_SHRINK = [ - [{ transform: 'scale(1)' }, { transform: 'scale(0.9)' }, { transform: 'scale(1)' }], - { +export const QUICK_SHRINK = { + keyframes: [{ transform: 'scale(1)' }, { transform: 'scale(0.9)' }, { transform: 'scale(1)' }], + options: { duration: 200, easing: 'ease-in-out', }, -]; +}; From c6401953ce0eca0fa17713f61c4cb105c5b9729c Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 16:31:06 +0200 Subject: [PATCH 03/18] chore(typechecking): add typechecking on buffer.js --- src/lib/buffer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/buffer.js b/src/lib/buffer.js index 3b52bb8bf..6289c0720 100644 --- a/src/lib/buffer.js +++ b/src/lib/buffer.js @@ -16,6 +16,7 @@ export class Buffer { */ constructor(onFlush, flushConditions) { this._onFlush = onFlush; + /** @type {Array} */ this._bucket = []; this._timeout = flushConditions.timeout; this._length = flushConditions.length; From 422c3316019145a289e392081273af858cf00176 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 16:33:11 +0200 Subject: [PATCH 04/18] chore(typechecking): fix typechecking on clipboard.js --- src/lib/clipboard.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/clipboard.js b/src/lib/clipboard.js index 6e3e66499..bcbb3d646 100644 --- a/src/lib/clipboard.js +++ b/src/lib/clipboard.js @@ -7,6 +7,7 @@ */ export async function copyToClipboard(text, html = null) { if (navigator.clipboard?.write != null) { + /** @type {{'text/plain': Blob, 'text/html'?: Blob}} */ const items = { 'text/plain': new Blob([text], { type: 'text/plain' }), }; @@ -16,7 +17,7 @@ export async function copyToClipboard(text, html = null) { // eslint-disable-next-line no-undef await navigator.clipboard.write([new ClipboardItem(items)]); } else if (document.execCommand != null) { - const listener = (e) => { + const listener = /** @param {ClipboardEvent} e*/ (e) => { e.clipboardData.setData('text/plain', text); if (html != null) { e.clipboardData.setData('text/html', html); From e69e248802c7a5088c8feca4b4e20d35f59d44f3 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 16:39:14 +0200 Subject: [PATCH 05/18] chore(typechecking): fix typechecking on color.js --- src/lib/color.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/lib/color.js b/src/lib/color.js index 8f8b0631f..eb6139a3f 100644 --- a/src/lib/color.js +++ b/src/lib/color.js @@ -22,7 +22,7 @@ export function hexToRgb(hex) { } /** - * + * Transforms the given RGB color into hex format. * @param {RgbColor} color * @return {string} */ @@ -31,7 +31,7 @@ export function rgbToHex(color) { } /** - * + * Transforms the given RGB color into HSL format. * @param {RgbColor} color * @return {HslColor} */ @@ -62,7 +62,7 @@ export function rgbToHsl(color) { } /** - * + * Transforms the given HSL color into RGB format. * @param {HslColor} hsl * @return {RgbColor} */ @@ -95,7 +95,7 @@ export function hslToRgb(hsl) { } /** - * + * Get the luminosity of the given RGB color * @param {RgbColor} color * @return {number} */ @@ -106,6 +106,7 @@ export function getLuminosity(color) { } /** + * Returns whether the given color is dark. * * @param {RgbColor} color * @return {boolean} @@ -131,7 +132,7 @@ export function getContrastRatio(color1, color2) { * @return {RgbColor} */ export function shadeColor(color, percent) { - const shade = (n) => { + const shade = /** @param {number} n */ (n) => { return Math.round(Math.max(0, Math.min(255, n + Math.round(2.55 * percent)))); }; @@ -142,10 +143,19 @@ export function shadeColor(color, percent) { }; } +/** + * @param {number} lighterLuminosity + * @param {number} darkerLuminosity + * @return {number} + */ function computeContrast(lighterLuminosity, darkerLuminosity) { return (lighterLuminosity + 0.05) / (darkerLuminosity + 0.05); } +/** + * @param {number} composant + * @return {number} + */ function getComposantValue(composant) { const c = composant / 255; if (c <= 0.03928) { From c14884e976724b5bb1732c0cb70d3e7da811e091 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:11:52 +0200 Subject: [PATCH 06/18] chore(typechecking): fix typechecking on date utils --- src/lib/date/date-formatter.js | 35 +++++++++++++++++++++++++--------- src/lib/date/date-utils.js | 10 +++++++++- src/lib/date/date.types.d.ts | 18 ++++++++--------- tsconfig.json | 1 + 4 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/lib/date/date-formatter.js b/src/lib/date/date-formatter.js index d6fd1f1ae..93fa46210 100644 --- a/src/lib/date/date-formatter.js +++ b/src/lib/date/date-formatter.js @@ -19,6 +19,10 @@ */ const DATE_TIME_FORMATS_BY_TIMEZONE = new Map(); +/** + * @param {Timezone} timezone + * @return {Intl.DateTimeFormat} + */ function getDateTimeFormat(timezone) { let format = DATE_TIME_FORMATS_BY_TIMEZONE.get(timezone); if (format == null) { @@ -84,6 +88,7 @@ export class DateFormatter { formatToParts(date) { const parts = this.toParts(date); + /** @type {DateFormattedParts} */ const result = { date: `${parts.year}-${parts.month}-${parts.day}`, separator: this._isIso ? 'T' : ' ', @@ -104,18 +109,14 @@ export class DateFormatter { /** * * @param {Date} date - * @param {(part: {value: string|number, type: 'part'|'separator'}) => *} mapper + * @param {(part: {value: string, type: 'part'|'separator'}) => *} mapper * @return {Array<*>} */ mapParts(date, mapper) { const parts = this.toParts(date); - const dateSeparator = { value: '-', type: 'separator' }; - const timeSeparator = { value: ':', type: 'separator' }; - const separator = { value: this._isIso ? 'T' : ' ', type: 'separator' }; - const part = (value) => { - return { value, type: 'part' }; - }; + const dateSeparator = separator('-'); + const timeSeparator = separator(':'); const items = [ part(parts.year), @@ -123,7 +124,7 @@ export class DateFormatter { part(parts.month), dateSeparator, part(parts.day), - separator, + separator(this._isIso ? 'T' : ' '), part(parts.hour), timeSeparator, part(parts.minute), @@ -149,10 +150,10 @@ export class DateFormatter { */ toParts(date) { const dtf = getDateTimeFormat(this._timezone); - const datePartsArray = dtf.formatToParts(date); const dateParts = Object.fromEntries(datePartsArray.map(({ type, value }) => [type, value])); + /** @type {DateParts} */ const result = { year: dateParts.year, month: dateParts.month, @@ -173,3 +174,19 @@ export class DateFormatter { return result; } } + +/** + * @param {string} value + * @return {{value: string, type: 'part'}} + */ +function part(value) { + return { value, type: 'part' }; +} + +/** + * @param {string} value + * @return {{value: string, type: 'separator'}} + */ +function separator(value) { + return { value, type: 'separator' }; +} diff --git a/src/lib/date/date-utils.js b/src/lib/date/date-utils.js index 7ce9a9b20..b1fed6a79 100644 --- a/src/lib/date/date-utils.js +++ b/src/lib/date/date-utils.js @@ -2,6 +2,7 @@ import { clampNumber } from '../utils.js'; /** * @typedef {import('./date.types.js').Timezone} Timezone + * @typedef {(date: Date, offset: number) => Date} DateShiftFunction */ export const SECOND = 1000; @@ -51,6 +52,7 @@ export function getNumberOfDaysInMonth(year, month) { // region Date shift const DATE_SHIFTER = { + /** @type {DateShiftFunction} */ Y: function (date, offset) { const d = cloneDate(date); const nextYear = date.getUTCFullYear() + offset; @@ -65,6 +67,7 @@ const DATE_SHIFTER = { return d; }, + /** @type {DateShiftFunction} */ M: function (date, offset) { const d = cloneDate(date); @@ -86,22 +89,27 @@ const DATE_SHIFTER = { return d; }, - + /** @type {DateShiftFunction} */ D: function (date, offset) { return DATE_SHIFTER._shift(date, offset * DAY); }, + /** @type {DateShiftFunction} */ H: function (date, offset) { return DATE_SHIFTER._shift(date, offset * HOUR); }, + /** @type {DateShiftFunction} */ m: function (date, offset) { return DATE_SHIFTER._shift(date, offset * MINUTE); }, + /** @type {DateShiftFunction} */ s: function (date, offset) { return DATE_SHIFTER._shift(date, offset * SECOND); }, + /** @type {DateShiftFunction} */ S: function (date, offset) { return DATE_SHIFTER._shift(date, offset); }, + /** @type {DateShiftFunction} */ _shift: function (date, offset) { return new Date(date.getTime() + offset); }, diff --git a/src/lib/date/date.types.d.ts b/src/lib/date/date.types.d.ts index 060c82ee3..ac8d70f2c 100644 --- a/src/lib/date/date.types.d.ts +++ b/src/lib/date/date.types.d.ts @@ -7,20 +7,20 @@ export interface DateFormattedParts { separator: 'T' | ' '; time: string; millisecond?: string; - timezone?: Timezone; + timezone?: string; } export type DateFormattedPart = keyof DateFormattedParts; export interface DateParts { - year: number; - month: number; - day: number; - hour: number; - minute: number; - second: number; - millisecond?: number; - timezone?: Timezone; + year: string; + month: string; + day: string; + hour: string; + minute: string; + second: string; + millisecond?: string; + timezone?: string; } export type DatePart = keyof DateParts; diff --git a/tsconfig.json b/tsconfig.json index 64d2558ea..e0a1a8411 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,7 @@ /* Language and Environment */ "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "lib": [ + "ES2021", "DOM", "DOM.Iterable" ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ From cc7b97d2f1687da07a729df16b6df9b81495610e Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:37:17 +0200 Subject: [PATCH 07/18] chore(typechecking): fix typechecking on ansi utils --- src/lib/ansi/ansi-palette-analyser.js | 18 ++++++++++++--- src/lib/ansi/ansi.js | 32 +++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/lib/ansi/ansi-palette-analyser.js b/src/lib/ansi/ansi-palette-analyser.js index a2f93efad..aa4481974 100644 --- a/src/lib/ansi/ansi-palette-analyser.js +++ b/src/lib/ansi/ansi-palette-analyser.js @@ -1,19 +1,26 @@ import { getContrastRatio, hexToRgb, isDark } from '../color.js'; -const colors = ['red', 'green', 'yellow', 'blue', 'magenta', 'cyan']; +/** + * @typedef {import('./ansi.types.js').AnsiPalette} AnsiPalette + * @typedef {keyof AnsiPalette} ColorsType + */ + +/** @type {Array} */ +const COLORS = ['red', 'green', 'yellow', 'blue', 'magenta', 'cyan']; /** - * * @param {AnsiPalette} palette */ export function analyzePalette(palette) { const background = hexToRgb(palette.background); + /** @type {Array} */ const colorsToTest = getColorsToTest(isDark(background)); const colorsCount = colorsToTest.length; let ratioSum = 0; let compliantCount = 0; + /** @type {Partial>} */ const contrasts = {}; colorsToTest.forEach((colorName) => { @@ -34,8 +41,13 @@ export function analyzePalette(palette) { }; } +/** + * @param {boolean} isDarkPalette + * @return {Array} + */ function getColorsToTest(isDarkPalette) { - const result = [...colors, isDarkPalette ? 'white' : 'black']; + const result = [...COLORS, isDarkPalette ? 'white' : 'black']; + // @ts-ignore return [...result, ...result.map((c) => `bright-${c}`)]; } diff --git a/src/lib/ansi/ansi.js b/src/lib/ansi/ansi.js index beabe1bf2..963084966 100644 --- a/src/lib/ansi/ansi.js +++ b/src/lib/ansi/ansi.js @@ -2,6 +2,10 @@ import ansiRegEx from 'ansi-regex'; import { css, html, unsafeCSS } from 'lit'; import { MemoryCache } from '../memory-cache.js'; +/** + * @typedef {import('./ansi.types.js').AnsiPart} AnsiPart + */ + /** @type {AnsiParser} - Lazy loaded parser */ let ansiParser; @@ -134,7 +138,7 @@ ANSI_COLORS.forEach((style) => { /** * Remove all ANSI escape codes from the given text. - * @param text + * @param {string} text * @return {string} */ export function stripAnsi(text) { @@ -145,6 +149,8 @@ export function stripAnsi(text) { * Converts the given text into Lit template according to the ANSI escape codes found in text. * * When using this, don't forget to include the `ansiPaletteStyle` CSS rules to a parent element. (see ./ansi-palette-style) + * + * @param {string} text */ export function ansiToLit(text) { if (ansiParser == null) { @@ -152,7 +158,7 @@ export function ansiToLit(text) { } const tokens = ansiParser.parse(text); - return tokens.map((token, i) => { + return tokens.map((token) => { if (token.styles.length === 0) { return token.text; } @@ -232,6 +238,11 @@ class AnsiParser { /** @type {Map>} */ const commonEscapes = new Map(); + /** + * @param {string} name + * @param {string} code + * @param {Array} escapes + */ const handleCode = (name, code, escapes) => { const ansiCode = toAnsi(code); this.codeToStyle.set(ansiCode, name); @@ -261,7 +272,7 @@ class AnsiParser { } /** - * @param str + * @param {string} str * @return {Array} */ parse(str) { @@ -269,7 +280,7 @@ class AnsiParser { } /** - * @param str + * @param {string} str * @return {Array} */ _doParse(str) { @@ -329,6 +340,11 @@ function addToIndexMap(map, key, value) { map.get(key).add(value); } +/** + * @param {Array} arr + * @param {T} val + * @template T + */ function removeElm(arr, val) { const i = arr.indexOf(val); if (i >= 0) { @@ -336,10 +352,18 @@ function removeElm(arr, val) { } } +/** + * @param {string|number} code + * @return {string} + */ function toAnsi(code) { return `\u001b[${code}m`; } +/** + * @param {string} ansiCode + * @return {string} + */ function fromAnsi(ansiCode) { return ansiCode.slice(2, ansiCode.length - 1); } From 425255f1bc4c598291a9bb7bd685b72f6f089ee5 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:38:32 +0200 Subject: [PATCH 08/18] chore(typechecking): fix typechecking on dom.js --- src/lib/dom.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/dom.js b/src/lib/dom.js index ef859e54d..aaa0a23e1 100644 --- a/src/lib/dom.js +++ b/src/lib/dom.js @@ -1,5 +1,9 @@ const timeoutCache = new WeakMap(); +/** + * @param {Element} parent + * @param {Element} child + */ export function scrollChildIntoParent(parent, child) { const oldTimeoutId = timeoutCache.get(parent); clearTimeout(oldTimeoutId); @@ -14,6 +18,10 @@ export function scrollChildIntoParent(parent, child) { timeoutCache.set(parent, newTimeoutId); } +/** + * @param {Element} parent + * @param {Element} child + */ function doScrollChildIntoParent(parent, child) { // In our situation, we don't need to handle borders and paddings const parentRect = parent.getBoundingClientRect(); From 0baf1a21c8d13775cc0e4f590b3feb83d39fc170 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:40:11 +0200 Subject: [PATCH 09/18] chore(typechecking): add ts-nocheck directive to immer.js --- src/lib/immer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/immer.js b/src/lib/immer.js index e1d67650f..13256bfcb 100644 --- a/src/lib/immer.js +++ b/src/lib/immer.js @@ -1,4 +1,6 @@ -// immer uses a non standard global property from Node.js "process" +// @ts-nocheck + +// immer uses a non-standard global property from Node.js "process" window.process = { env: { NODE_ENV: 'production', From 42d4c4bff52599ba35045abfef25ceee04747930 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:41:31 +0200 Subject: [PATCH 10/18] chore(typechecking): fix typechecking on memory-cache.js --- src/lib/memory-cache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/memory-cache.js b/src/lib/memory-cache.js index 538df5e44..845aa8d87 100644 --- a/src/lib/memory-cache.js +++ b/src/lib/memory-cache.js @@ -18,7 +18,7 @@ export class MemoryCache { /** @type {Map} */ this._map = new Map(); - /** @type {Array} */ + /** @type {Array} */ this._keys = []; } From 735a684bfda58cc105eec3f2e938adf1a2bb4c3d Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:53:17 +0200 Subject: [PATCH 11/18] chore(typechecking): fix typechecking on notifications.js --- src/components/common.types.d.ts | 12 ++++++++++++ src/lib/notifications.js | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/common.types.d.ts b/src/components/common.types.d.ts index c2516c785..d188e2ad1 100644 --- a/src/components/common.types.d.ts +++ b/src/components/common.types.d.ts @@ -214,3 +214,15 @@ interface EnvVarEditorStateLoaded { /* endregion */ export type NotificationIntent = 'info' | 'success' | 'warning' | 'danger'; + +export interface Notification { + message: string | Node; + title?: string; + intent: NotificationIntent; + options?: NotificationOptions; +} + +export interface NotificationOptions { + timeout?: number; + closeable?: boolean; +} diff --git a/src/lib/notifications.js b/src/lib/notifications.js index a0b3afc47..06fd3f28f 100644 --- a/src/lib/notifications.js +++ b/src/lib/notifications.js @@ -1,7 +1,7 @@ import { dispatchCustomEvent } from './events.js'; /** - * @typedef {import('../toast/types.js').Notification} Notification + * @typedef {import('../components/common.types.js').Notification} Notification */ /** @@ -14,7 +14,7 @@ export function notify(notification, target = window) { } /** - * @param {string} message + * @param {string|Node} message * @param {string} [title] * @return {CustomEvent} the cc:notify event that has been dispatched. */ @@ -27,7 +27,7 @@ export function notifyError(message, title) { } /** - * @param {string} message + * @param {string|Node} message * @param {string} [title] * @return {CustomEvent} the cc:notify event that has been dispatched. */ From 4386686e8039cbe83ff5f673678da02355965db5 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:57:15 +0200 Subject: [PATCH 12/18] chore(typechecking): fix typechecking on shadow-dom-utils.js --- src/lib/shadow-dom-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/shadow-dom-utils.js b/src/lib/shadow-dom-utils.js index aeb4a76b5..0e0fa7294 100644 --- a/src/lib/shadow-dom-utils.js +++ b/src/lib/shadow-dom-utils.js @@ -66,7 +66,7 @@ export function elementsFromPoint(x, y, root = document) { } else if (elements.includes(items[0])) { shadow = null; } else { - elements = [...items, elements]; + elements = [...items, ...elements]; shadow = items[0].shadowRoot; } } From 37cc3a925493aae8530f154655645986fe893e9c Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 29 Jul 2024 17:57:26 +0200 Subject: [PATCH 13/18] chore(typechecking): fix typechecking on remote-assets.js --- src/lib/remote-assets.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib/remote-assets.js b/src/lib/remote-assets.js index af96f0b17..86f592d80 100644 --- a/src/lib/remote-assets.js +++ b/src/lib/remote-assets.js @@ -1,7 +1,15 @@ +/** + * @param {string|null} countryCode + * @return {string|null} + */ export function getFlagUrl(countryCode) { - return countryCode != null ? `https://assets.clever-cloud.com/flags/${countryCode.toLowerCase()}.svg` : countryCode; + return countryCode != null ? `https://assets.clever-cloud.com/flags/${countryCode.toLowerCase()}.svg` : null; } +/** + * @param {string|null} providerSlug + * @return {string|null} + */ export function getInfraProviderLogoUrl(providerSlug) { - return providerSlug != null ? `https://assets.clever-cloud.com/infra/${providerSlug}.svg` : providerSlug; + return providerSlug != null ? `https://assets.clever-cloud.com/infra/${providerSlug}.svg` : null; } From bc5f18498cf3920b64869b82d81358e9bb1131fe Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Wed, 31 Jul 2024 10:02:56 +0200 Subject: [PATCH 14/18] chore(typechecking): fix typechecking on xml-parser.js --- src/lib/xml-parser.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/xml-parser.js b/src/lib/xml-parser.js index 3ea6c98b7..8f0130b2d 100644 --- a/src/lib/xml-parser.js +++ b/src/lib/xml-parser.js @@ -1,12 +1,12 @@ /** - * @typedef {import('../homepage/types.js').Article} Article + * @typedef {import('../components/cc-article-card/cc-article-card.types.js').ArticleCard} ArticleCard */ /** * Parse an RSS feed XML document into a list of articles. * @param {String} xmlStr - Raw XML document (RSS feed) as a string. * @param {Number} limit - Limit the number of articles from the feed. - * @returns {Article[]} + * @returns {Array} */ export function parseRssFeed(xmlStr, limit = 9) { if (limit <= 0) { @@ -28,8 +28,10 @@ export function parseRssFeed(xmlStr, limit = 9) { const dateRaw = node.querySelector('pubDate').textContent; const date = new Date(dateRaw).toISOString(); + // @ts-ignore const descriptionText = node.querySelector('description').childNodes[0].data; const descriptionNode = new DOMParser().parseFromString(descriptionText, 'text/html'); + // @ts-ignore const banner = descriptionNode.body?.querySelector('.wp-post-image')?.src ?? null; // TODO: we shouldn't have to do the `??` part here but somehow as of 2023-10-18 an article is causing some trouble. We'll have to keep track of this. const description = From 7fe229ff7185034046756c87b3ad54a07b8ecb3e Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Wed, 31 Jul 2024 10:38:41 +0200 Subject: [PATCH 15/18] chore(typechecking): fix typechecking on api-helpers.js --- src/components/common.types.d.ts | 2 +- src/lib/api-helpers.js | 121 +++++++++++++++++++++++++------ src/lib/send-to-api.js | 16 ++-- 3 files changed, 109 insertions(+), 30 deletions(-) diff --git a/src/components/common.types.d.ts b/src/components/common.types.d.ts index d188e2ad1..9a5636882 100644 --- a/src/components/common.types.d.ts +++ b/src/components/common.types.d.ts @@ -63,7 +63,7 @@ interface InvoiceAmount { export interface Invoice { downloadUrl: string; emissionDate: string; - invoiceHtml: string; + invoiceHtml?: string; number: string; paymentUrl: string; status: InvoiceStatusType; diff --git a/src/lib/api-helpers.js b/src/lib/api-helpers.js index 88fe19219..3029328fc 100644 --- a/src/lib/api-helpers.js +++ b/src/lib/api-helpers.js @@ -1,36 +1,86 @@ +// @ts-expect-error FIXME: remove when clever-client exports types import { get as getApp } from '@clevercloud/client/esm/api/v2/application.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { getAllInvoices, getInvoice } from '@clevercloud/client/esm/api/v4/billing.js'; -import { getAllZones } from '@clevercloud/client/esm/api/v4/product.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { addOauthHeader } from '@clevercloud/client/esm/oauth.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { pickNonNull } from '@clevercloud/client/esm/pick-non-null.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { prefixUrl } from '@clevercloud/client/esm/prefix-url.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { ONE_DAY } from '@clevercloud/client/esm/with-cache.js'; import { sendToApi } from './send-to-api.js'; import { asyncMap } from './utils.js'; +/** + * @typedef {import('./send-to-api.types.js').ApiConfig} ApiConfig + * @typedef {import('../components/common.types.js').Invoice} Invoice + */ + +/** + * @param {object} options + * @param {ApiConfig} options.apiConfig + * @param {AbortSignal} options.signal + * @param {string} options.ownerId + * @param {string} options.appId + * @return {Promise<{name: string}>} + */ export function fetchApp({ apiConfig, signal, ownerId, appId }) { return getApp({ id: ownerId, appId }).then(sendToApi({ apiConfig, signal })); } +/** + * @param {object} options + * @param {ApiConfig} options.apiConfig + * @param {AbortSignal} options.signal + * @param {string} options.ownerId + * @param {string} options.invoiceNumber + * @return {Promise} + */ export async function fetchInvoice({ apiConfig, signal, ownerId, invoiceNumber }) { return getInvoice({ id: ownerId, invoiceNumber, type: '' }) .then(sendToApi({ apiConfig, signal })) - .then((invoice) => formatInvoice(apiConfig, ownerId, invoice)); + .then(/** @param {{[p: string]: any}} invoice*/ (invoice) => formatInvoice(apiConfig, ownerId, invoice)); } +/** + * @param {object} options + * @param {ApiConfig} options.apiConfig + * @param {AbortSignal} options.signal + * @param {string} options.ownerId + * @param {string} options.invoiceNumber + * @return {Promise} + */ export async function fetchInvoiceHtml({ apiConfig, signal, ownerId, invoiceNumber }) { return getInvoice({ id: ownerId, invoiceNumber, type: '.html' }).then(sendToApi({ apiConfig, signal })); } +/** + * @param {object} options + * @param {ApiConfig} options.apiConfig + * @param {AbortSignal} options.signal + * @param {string} options.ownerId + * @return {Promise>} + */ export async function fetchAllInvoices({ apiConfig, signal, ownerId }) { // We ask for all invoices by default for now return getAllInvoices({ id: ownerId, since: '2010-08-01T00:00:00.000Z' }) .then(sendToApi({ apiConfig, signal })) - .then((invoices) => { - return asyncMap(invoices, async (i) => formatInvoice(apiConfig, ownerId, i)); - }); + .then( + /** @param {Array<{[p: string]: any}>} invoices */ (invoices) => { + return asyncMap(invoices, async (i) => formatInvoice(apiConfig, ownerId, i)); + }, + ); } +/** + * + * @param {ApiConfig} apiConfig + * @param {string} ownerId + * @param {{[p: string]: any}} rawInvoice + * @return {Promise} + */ async function formatInvoice(apiConfig, ownerId, rawInvoice) { return { number: rawInvoice.invoice_number, @@ -46,17 +96,30 @@ async function formatInvoice(apiConfig, ownerId, rawInvoice) { }; } +/** + * @param {ApiConfig} apiConfig + * @param {string} ownerId + * @param {string} invoiceNumber + * @return {Promise} + */ function getDownloadUrl(apiConfig, ownerId, invoiceNumber) { return getInvoice({ id: ownerId, invoiceNumber, type: '.pdf' }) .then(prefixUrl(apiConfig.API_HOST)) .then(addOauthHeader(apiConfig)) - .then((requestParams) => { - const url = new URL(requestParams.url); - url.searchParams.set('authorization', btoa(requestParams.headers.Authorization)); - return url.toString(); - }); + .then( + /** @param {{url: string, headers: {Authorization: string}}} requestParams */ (requestParams) => { + const url = new URL(requestParams.url); + url.searchParams.set('authorization', btoa(requestParams.headers.Authorization)); + return url.toString(); + }, + ); } +/** + * @param {string} ownerId + * @param {string} invoiceNumber + * @return {string} + */ function getPaymentUrl(ownerId, invoiceNumber) { return ownerId == null || ownerId.startsWith('user_') ? `/users/me/invoices/${invoiceNumber}` @@ -66,7 +129,7 @@ function getPaymentUrl(ownerId, invoiceNumber) { // TODO: move to clever-client /** * GET /v4/billing/price-system - * @param {Object} params + * @param {object} params * @param {String} params.zone_id */ export function getPriceSystem(params) { @@ -80,6 +143,13 @@ export function getPriceSystem(params) { }); } +/** + * + * @param {object} params + * @param {AbortSignal} params.signal + * @param {string} params.zoneId + * @return {Promise<*>} + */ export function fetchPriceSystem({ signal, zoneId }) { // eslint-disable-next-line camelcase return getPriceSystem({ zone_id: zoneId }).then(sendToApi({ signal, cacheDelay: ONE_DAY })); @@ -89,8 +159,8 @@ export function fetchPriceSystem({ signal, zoneId }) { // Tmp Grafana API calls /** * GET /v4/saas/grafana/{id} - * @param {Object} params - * @param {String} params.id + * @param {object} params + * @param {string} params.id */ export function getGrafanaOrganisation(params) { return Promise.resolve({ @@ -102,8 +172,8 @@ export function getGrafanaOrganisation(params) { /** * POST /v4/saas/grafana/{id} - * @param {Object} params - * @param {String} params.id + * @param {object} params + * @param {string} params.id */ export function createGrafanaOrganisation(params) { return Promise.resolve({ @@ -116,7 +186,7 @@ export function createGrafanaOrganisation(params) { /** * DELETE /v4/saas/grafana/{id} * @param {Object} params - * @param {String} params.id + * @param {string} params.id */ export function deleteGrafanaOrganisation(params) { return Promise.resolve({ @@ -128,8 +198,8 @@ export function deleteGrafanaOrganisation(params) { /** * POST /v4/saas/grafana/{id}/reset - * @param {Object} params - * @param {String} params.id + * @param {object} params + * @param {string} params.id */ export function resetGrafanaOrganisation(params) { return Promise.resolve({ @@ -139,16 +209,19 @@ export function resetGrafanaOrganisation(params) { }); } -export async function fetchAllZones({ signal }) { - return getAllZones().then(sendToApi({ signal, cacheDelay: ONE_DAY })); -} - // TODO: move this to clever client -export function getAppMetrics(params) { +/** + * + * @param {object} params + * @param {string} params.id + * @param {string} params.appId + * @return {Promise<{headers: {Accept: string}, method: string, url: string}>} + */ +export function getAppMetrics({ id, appId }) { return Promise.resolve({ method: 'get', // TODO: Handle query params properly. (https://github.com/CleverCloud/clever-client.js/issues/76) - url: `/v4/stats/organisations/${params.id}/resources/${params.appId}/metrics?interval=P1D&span=PT1H&only=cpu&only=mem`, + url: `/v4/stats/organisations/${id}/resources/${appId}/metrics?interval=P1D&span=PT1H&only=cpu&only=mem`, headers: { Accept: 'application/json' }, }); } diff --git a/src/lib/send-to-api.js b/src/lib/send-to-api.js index 8732c5533..b06b54112 100644 --- a/src/lib/send-to-api.js +++ b/src/lib/send-to-api.js @@ -1,8 +1,14 @@ +// @ts-expect-error FIXME: remove when clever-client exports types import { addOauthHeader } from '@clevercloud/client/esm/oauth.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { prefixUrl } from '@clevercloud/client/esm/prefix-url.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { execWarpscript } from '@clevercloud/client/esm/request-warp10.fetch.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { request } from '@clevercloud/client/esm/request.fetch.js'; +// @ts-expect-error FIXME: remove when clever-client exports types; import { withCache } from '@clevercloud/client/esm/with-cache.js'; +// @ts-expect-error FIXME: remove when clever-client exports types import { withOptions } from '@clevercloud/client/esm/with-options.js'; import { dispatchCustomEvent } from './events.js'; @@ -13,10 +19,10 @@ import { dispatchCustomEvent } from './events.js'; /** * @param {Object} settings - * @param {ApiConfig} settings.apiConfig + * @param {ApiConfig} [settings.apiConfig] * @param {AbortSignal} [settings.signal] - * @param {Number} [settings.cacheDelay] - * @param {Number} [settings.timeout] + * @param {number} [settings.cacheDelay] + * @param {number} [settings.timeout] * @return {(requestParams: Object) => Promise} */ export function sendToApi({ apiConfig, signal, cacheDelay, timeout }) { @@ -41,8 +47,8 @@ export function sendToApi({ apiConfig, signal, cacheDelay, timeout }) { * @param {Object} settings * @param {Warp10ApiConfig} settings.apiConfig * @param {AbortSignal} [settings.signal] - * @param {Number} [settings.cacheDelay] - * @param {Number} [settings.timeout] + * @param {number} [settings.cacheDelay] + * @param {number} [settings.timeout] * @return {(requestParams: Object) => Promise} */ export function sendToWarp({ apiConfig, signal, cacheDelay, timeout }) { From bb87473df2ba6fb92244e3d08605a3729470fd73 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Wed, 31 Jul 2024 12:38:49 +0200 Subject: [PATCH 16/18] chore(typechecking): fix typechecking on smart --- src/lib/define-smart-component.js | 93 ++++++++++++++++-------------- src/lib/smart-component.types.d.ts | 47 +++++++++++++++ src/lib/smart-manager.js | 60 +++++++++---------- src/lib/smart-symbols.js | 4 ++ 4 files changed, 131 insertions(+), 73 deletions(-) create mode 100644 src/lib/smart-component.types.d.ts create mode 100644 src/lib/smart-symbols.js diff --git a/src/lib/define-smart-component.js b/src/lib/define-smart-component.js index a8372f8ff..a3fa260dd 100644 --- a/src/lib/define-smart-component.js +++ b/src/lib/define-smart-component.js @@ -1,45 +1,26 @@ import { produce } from './immer.js'; import { defineSmartComponentCore } from './smart-manager.js'; - -const META = Symbol('META'); - -/** - * @typedef {Element} SmartContainer - * @property {Object} context - */ - -/** - * @typedef {Object|((property: Object) => void)} CallbackOrObject - */ +import { META } from './smart-symbols.js'; /** - * @typedef {Object} SmartDefinitionParam - * @property {TypeHint} type - * @property {boolean} [optional=false] - * @template TypeHint + * @typedef {import('./smart-component.types.js').SmartContainer} SmartContainer + * @typedef {import('./smart-component.types.js').SmartComponent} SmartComponent + * @typedef {import('./smart-component.types.js').SmartComponentDefinition} SmartComponentDefinition + * @typedef {import('./smart-component.types.js').SmartContext} SmartContext + * @typedef {import('./smart-component.types.js').OnEventCallback} OnEventCallback + * @typedef {import('./smart-component.types.js').CallbackOrObject} CallbackOrObject + * @typedef {import('./smart-component.types.js').UpdateComponentCallback} UpdateComponentCallback */ /** - * @param {Object} definition - * @param {string} definition.selector - * @param {{[name: string]: SmartDefinitionParam}} definition.params - * @param {({ - * container?: SmartContainer, - * component?: Element, - * context?: Object, - * onEvent?: (type: string, listener: (detail: Object) => void) => void, - * updateComponent?: ( - * type: string, - * callbackOrObject: CallbackOrObject, - * ) => void, - * signal?: AbortSignal, - * }) => void} definition.onContextUpdate + * + * @param {SmartComponentDefinition} definition */ export function defineSmartComponent(definition) { defineSmartComponentCore({ selector: definition.selector, params: definition.params, - onConnect(container, component) { + onConnect(_container, component) { if (component[META] == null) { component[META] = new Map(); } @@ -68,11 +49,14 @@ export function defineSmartComponent(definition) { // Prepare a helper function to attach event listeners on the component // and make sure they're removed if the signal is aborted + + /** @type {OnEventCallback} */ function onEvent(type, listener) { component.addEventListener( type, (e) => { - listener(e.detail); + const event = /** @type {CustomEvent} */ (e); + listener(event.detail); }, { signal }, ); @@ -87,30 +71,53 @@ export function defineSmartComponent(definition) { target.addEventListener( 'update-component', - (event) => { - const { property, callbackOrObject } = event.data; - if (typeof callbackOrObject === 'function') { - if (component[property] != null) { - component[property] = produce(component[property], callbackOrObject); - } - } else { - component[property] = callbackOrObject; - } + (e) => { + const event = /** @type {UpdateComponentEvent} */ (e); + handleUpdateComponent(component, event.property, event.callbackOrObject); }, { signal }, ); + /** @type {UpdateComponentCallback} */ function updateComponent(property, callbackOrObject) { - const event = new Event('update-component'); - event.data = { property, callbackOrObject }; + const event = new UpdateComponentEvent(property, callbackOrObject); target.dispatchEvent(event); } definition.onContextUpdate({ container, component, context, onEvent, updateComponent, signal }); }, - onDisconnect(container, component) { + onDisconnect(_container, component) { component[META].get(definition).abortController?.abort(); component[META].delete(definition); }, }); } + +class UpdateComponentEvent extends Event { + /** + * @param {string} property + * @param {CallbackOrObject} callbackOrObject + */ + constructor(property, callbackOrObject) { + super('update-component'); + this.property = property; + this.callbackOrObject = callbackOrObject; + } +} + +/** + * + * @param {SmartComponent} component + * @param {string} property + * @param {CallbackOrObject} callbackOrObject + */ +function handleUpdateComponent(component, property, callbackOrObject) { + const c = /** @type {{[p:property]: any}} */ (component); + if (typeof callbackOrObject === 'function') { + if (c[property] != null) { + c[property] = produce(c[property], callbackOrObject); + } + } else { + c[property] = callbackOrObject; + } +} diff --git a/src/lib/smart-component.types.d.ts b/src/lib/smart-component.types.d.ts new file mode 100644 index 000000000..fc5cabb75 --- /dev/null +++ b/src/lib/smart-component.types.d.ts @@ -0,0 +1,47 @@ +import { COMPONENTS, CURRENT_CONTEXT, LAST_CONTEXT, META } from './smart-symbols.js'; + +export interface SmartContainer extends Element { + [COMPONENTS]?: Map>; + [CURRENT_CONTEXT]?: SmartContext; +} + +export interface SmartComponent extends Element { + [LAST_CONTEXT]?: SmartContext; + [META]?: Map; +} + +export interface SmartComponentCoreDefinition { + selector: string; + params?: Record; + onConnect?: (container: SmartContainer, component: SmartComponent) => void; + onContextUpdate?: (container: SmartContainer, component: SmartComponent, context: SmartContext) => void; + onDisconnect?: (container: SmartContainer, component: SmartComponent) => void; +} + +export interface SmartComponentDefinition { + selector: string; + params: Record; + onContextUpdate: (args: OnContextUpdateArgs) => void | Promise; +} + +export interface SmartDefinitionParam { + type: TypeHint; + optional?: boolean; +} + +export type SmartContext = Record; + +export type OnEventCallback = (type: string, listener: (detail: any) => void) => void; + +export type UpdateComponentCallback = (propertyName: string, property: CallbackOrObject) => void; + +export interface OnContextUpdateArgs { + container: SmartContainer; + component: SmartComponent; + context: SmartContext; + signal: AbortSignal; + onEvent: OnEventCallback; + updateComponent: UpdateComponentCallback; +} + +export type CallbackOrObject = T | ((property: T) => void); diff --git a/src/lib/smart-manager.js b/src/lib/smart-manager.js index 5e2d8fa2d..b3c15cfef 100644 --- a/src/lib/smart-manager.js +++ b/src/lib/smart-manager.js @@ -1,5 +1,14 @@ +import { COMPONENTS, CURRENT_CONTEXT, LAST_CONTEXT } from './smart-symbols.js'; import { objectEquals } from './utils.js'; +/** + * @typedef {import('./smart-component.types.js').SmartContainer} SmartContainer + * @typedef {import('./smart-component.types.js').SmartComponent} SmartComponent + * @typedef {import('./smart-component.types.js').SmartComponentCoreDefinition} SmartComponentCoreDefinition + * @typedef {import('./smart-component.types.js').SmartContext} SmartContext + * @typedef {import('./smart-component.types.js').SmartDefinitionParam} SmartDefinitionParam + */ + // In the global space of this module (for any module importing it), we maintain: // * a rootContext object // * a smartContainers Set with all containers currently in the page @@ -12,28 +21,16 @@ import { objectEquals } from './utils.js'; // On each component, we maintain: // * an object with the last context on component[LAST_CONTEXT] -/** - * @typedef SmartComponentDefinition - * @property {String} selector - * @property {Object} [params] - * @property {Function} [onConnect] - * @property {Function} [onContextUpdate] - * @property {Function} [onDisconnect] - */ - -const COMPONENTS = Symbol('COMPONENTS'); -const CURRENT_CONTEXT = Symbol('CURRENT_CONTEXT'); -const LAST_CONTEXT = Symbol('LAST_CONTEXT'); let rootContext = {}; -/** @type {Set} */ +/** @type {Set} */ const smartContainers = new Set(); -/** @type {Set} */ +/** @type {Set} */ const smartComponentDefinitions = new Set(); /** - * @param {CcSmartContainer} container + * @param {SmartContainer} container * @param {AbortSignal} signal */ export function observeContainer(container, signal) { @@ -62,7 +59,7 @@ export function observeContainer(container, signal) { } /** - * @param {SmartComponentDefinition} definition + * @param {SmartComponentCoreDefinition} definition * @param {AbortSignal} [signal] */ export function defineSmartComponentCore(definition, signal) { @@ -88,16 +85,19 @@ export function defineSmartComponentCore(definition, signal) { } function updateEverything() { + /** @type {Array<[SmartContainer, SmartComponentCoreDefinition, SmartComponent]>} */ const allDisconnectedComponents = []; + /** @type {Array<[SmartContainer, SmartComponentCoreDefinition, SmartComponent]>} */ const allConnectedComponents = []; + /** @type {Array<[SmartContainer, SmartComponentCoreDefinition, SmartComponent]>} */ const allIdleComponents = []; smartContainers.forEach((container) => { smartComponentDefinitions.forEach((definition) => { + /** @type {Array} */ const allDefinitionComponents = Array.from(container.querySelectorAll(definition.selector)).filter( (c) => closestParent(c, 'cc-smart-container') === container, ); - const previousComponents = container[COMPONENTS].get(definition) ?? []; container[COMPONENTS].set(definition, allDefinitionComponents); @@ -132,7 +132,7 @@ function updateEverything() { } /** - * @param {CcSmartContainer} container + * @param {SmartContainer} container * @param {Object} context */ export function updateContext(container, context) { @@ -149,9 +149,9 @@ export function updateRootContext(context) { } /** - * @param {CcSmartComponent} container - * @param {SmartComponentDefinition} definition - * @param {Element} component + * @param {SmartContainer} container + * @param {SmartComponentCoreDefinition} definition + * @param {SmartComponent} component */ function connectComponent(container, definition, component) { component[LAST_CONTEXT] = {}; @@ -159,9 +159,9 @@ function connectComponent(container, definition, component) { } /** - * @param {CcSmartComponent} container - * @param {SmartComponentDefinition} definition - * @param {Element} component + * @param {SmartContainer} container + * @param {SmartComponentCoreDefinition} definition + * @param {SmartComponent} component */ function updateComponentContext(container, definition, component) { const currentContext = { ...rootContext, ...container[CURRENT_CONTEXT] }; @@ -174,9 +174,9 @@ function updateComponentContext(container, definition, component) { } /** - * @param {CcSmartComponent} container - * @param {SmartComponentDefinition} definition - * @param {Element} component + * @param {SmartContainer} container + * @param {SmartComponentCoreDefinition} definition + * @param {SmartComponent} component */ function disconnectComponent(container, definition, component) { delete component[LAST_CONTEXT]; @@ -197,8 +197,8 @@ function closestParent(element, selector) { /** * - * @param {Object|null} source - * @param {Object|null} keyObject + * @param {SmartContext|null} source + * @param {Record|null} keyObject * @return {Object} */ function filterContext(source, keyObject) { @@ -210,6 +210,6 @@ function filterContext(source, keyObject) { } const newEntries = Object.keys(keyObject) .map((name) => [name, source[name]]) - .filter(([name, value]) => value !== undefined); + .filter(([, value]) => value !== undefined); return Object.fromEntries(newEntries); } diff --git a/src/lib/smart-symbols.js b/src/lib/smart-symbols.js new file mode 100644 index 000000000..952e24846 --- /dev/null +++ b/src/lib/smart-symbols.js @@ -0,0 +1,4 @@ +export const COMPONENTS = Symbol('COMPONENTS'); +export const CURRENT_CONTEXT = Symbol('CURRENT_CONTEXT'); +export const LAST_CONTEXT = Symbol('LAST_CONTEXT'); +export const META = Symbol('META'); From 06a101255cabbdb17959456a7e00b32ee179f330 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 9 Sep 2024 15:33:15 +0200 Subject: [PATCH 17/18] chore(typechecking): include almost all src/lib/* to ci typecheck --- tsconfig.ci.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tsconfig.ci.json b/tsconfig.ci.json index ff5c55591..13b72d3f3 100644 --- a/tsconfig.ci.json +++ b/tsconfig.ci.json @@ -3,11 +3,17 @@ // as opposed to the `tsconfig.json` file used for typechecking within IDEs // Every file passing typechecking should be added in the `include` array below "include": [ - "src/lib/i18n/**/*.js", - "src/lib/utils.js", + "src/lib/**/*.js", "src/translations/**/*.js", "tasks/typechecking-stats.js", ], + "exclude": [ + "src/lib/leaflet-esm.js", + "src/lib/leaflet-heat.js", + "src/lib/pricing.js", + "src/lib/product.js", + "src/lib/simpleheat.js", + ], "extends": "./tsconfig.json", "compilerOptions": { // FIXME: From 691782125497bda53e03086fbd766d3cf9795e42 Mon Sep 17 00:00:00 2001 From: Pierre DE SOYRES Date: Mon, 9 Sep 2024 14:58:17 +0200 Subject: [PATCH 18/18] chore(typecheck:stats): take into account the excluded patterns --- tasks/typechecking-stats.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tasks/typechecking-stats.js b/tasks/typechecking-stats.js index f687d18c7..1e1bf8de2 100644 --- a/tasks/typechecking-stats.js +++ b/tasks/typechecking-stats.js @@ -39,10 +39,24 @@ const categories = { Tasks: ['tasks/**/*.js'], }; -async function run() { +/** + * @return {Promise>} + */ +async function getAllCheckedFiles() { const tsconfigJson = await fs.readFile('./tsconfig.ci.json', 'utf8'); const tsconfig = json5.parse(tsconfigJson); - const allCheckedFiles = await globAll(tsconfig.include); + + /** @type {Array} */ + const includePatterns = tsconfig.include; + /** @type {Array} */ + const excludePatterns = tsconfig.exclude; + const patterns = includePatterns.concat(excludePatterns.map((p) => `!${p}`)); + + return await globAll(patterns); +} + +async function run() { + const allCheckedFiles = await getAllCheckedFiles(); const results = await Promise.all( Object.entries(categories).map(async ([categoryName, patterns]) => {