From 8cae4fef39150b36bb6f721f44bd4b79d2c9315b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= Date: Thu, 7 Mar 2024 01:18:11 -0400 Subject: [PATCH] stricter lint; switch to `'` --- .eslintrc.js | 180 ++++++++++++++++++++++++---------------------- package-lock.json | 4 +- package.json | 2 +- src/main.js | 38 +++++----- 4 files changed, 115 insertions(+), 109 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f257c8c..d56f802 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,101 +1,107 @@ -'use strict' -//eslint-disable-next-line no-implicit-globals -const m = 'Use arrow fn instead.' +"use strict" +/* +eslint +no-magic-numbers: off, +no-implicit-globals: off, +*/ + +// shorthands to prevent typos +const + E = "error", + W = "warn" + +/** +regex pattern of intentionally unused identifiers +*/ +const UNUSED_ID = "^(_|(foo)?(ba[rz])?|bruh|yeet|gyatt?|amon?gus)$" //eslint-disable-next-line no-undef module.exports = { - env: { - browser: true, - es2021: true - }, - extends: 'eslint:recommended', - parserOptions: { - ecmaVersion: 'latest' - }, + env: { browser: true, es2022: true }, + parserOptions: { ecmaVersion: "latest" }, + + extends: "eslint:recommended", rules: { - 'no-magic-numbers': [ - 'warn', + "no-unused-expressions": W, + "no-unused-vars": [ + W, { - ignore: [ - -1, - 0, - 1, - 2 - ], - ignoreArrayIndexes: true, - ignoreDefaultValues: true, - enforceConst: true + varsIgnorePattern: UNUSED_ID, + argsIgnorePattern: UNUSED_ID } ], - 'no-unused-vars': [ - 'warn', + "no-magic-numbers": [ + W,// too many false-positives { - varsIgnorePattern: '^_$', - argsIgnorePattern: '^_$' - } - ], - 'no-param-reassign': 'error', - 'no-implicit-globals': [ - 'error', - { - lexicalBindings: true - } - ],/* - 'no-restricted-syntax': [ - 'error', - { - selector: 'FunctionDeclaration', - message: m - }, - { - selector: 'FunctionExpression', - message: m - } - ],*/ - 'no-empty-function': 'error', - 'no-loop-func': 'error', - 'no-lone-blocks': 'error', - 'no-constant-binary-expression': 'error', - 'no-self-compare': 'error', - 'no-unmodified-loop-condition': 'error', - 'no-unreachable-loop': 'error', - 'no-extra-label': 'error', - 'no-else-return': [ - 'error', - { - 'allowElseIf': false + ignore: [-1, 0, 1, 2], + ignoreArrayIndexes: true, + ignoreDefaultValues: true, + enforceConst: true } ], - 'require-atomic-updates': 'error', - 'no-eval': 'error', - 'no-implied-eval': 'error', - 'dot-notation': 'error', - 'no-array-constructor': 'error', - 'max-depth': 'warn', - 'max-nested-callbacks': [ - 'error', - 3 - ], - 'max-params': [ - 'error', - 4 - ], - 'indent': [ - 'error', - 'tab' - ], - 'linebreak-style': [ - 'error', - 'unix' + // Rust certified + "prefer-const": E, + /* + this is not forbidden, it's just to make mutation intentional. + to-do: replace by this proposal: + https://github.com/Fishrock123/proposal-const-function-arguments + */"no-param-reassign": E,// should it be `W`? + "no-var": E, + "no-implicit-globals": [E, { lexicalBindings: true }], + + "no-empty-function": E, + "no-loop-func": E, + "no-lone-blocks": E, + + "no-constant-binary-expression": E, + "no-self-compare": E, + + "no-unmodified-loop-condition": E, + "no-unreachable-loop": E, + + "no-extra-label": E, + + // guard-clauses are better + "no-else-return": [E, { "allowElseIf": false }], + "no-useless-return": E, + "no-unneeded-ternary": [E, { "defaultAssignment": false }], + "no-useless-computed-key": [E, { "enforceForClassMembers": true }], + "no-useless-concat": E, + "no-useless-constructor": E, + "no-useless-rename": E, + "object-shorthand": E, + + "require-atomic-updates": E, + + "no-eval": E, + "no-implied-eval": E, + "no-script-url": E, + + "dot-notation": E, + "no-array-constructor": E, + "no-sequences": E, + + // prefer Object bags + "max-params": [E, 4], + "max-depth": W, + // avoid CB-Hell + "max-nested-callbacks": [E, 3], + indent: [E, "tab"], + "linebreak-style": [E, "unix"], + "no-template-curly-in-string": W, + quotes: [ + E, + // "single" is cleaner, + // but "double" is more consistent with JSON + "double" ], - 'no-template-curly-in-string': 'warn', - 'quotes': [ - 'error', - 'single' + semi: [ + E, + // ASI is confusing, regardless of what you do + "never" ], - 'semi': [ - 'error', - 'never' - ] + // GH-issues can be used as alt, + // that's why no `W` + "no-warning-comments": [E, { "terms": ["todo", "to-do"] }] } } diff --git a/package-lock.json b/package-lock.json index 1e02719..56a9d98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rgb-digital-rain", - "version": "0.34.0", + "version": "0.35.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rgb-digital-rain", - "version": "0.34.0", + "version": "0.35.0", "license": "AGPL-3.0-or-later", "devDependencies": { "eslint": "^8.57.0" diff --git a/package.json b/package.json index 7dd81a9..7f1f220 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rgb-digital-rain", - "version": "0.34.0", + "version": "0.35.0", "main": "src/main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/src/main.js b/src/main.js index 875b93b..aa1c5c7 100644 --- a/src/main.js +++ b/src/main.js @@ -1,4 +1,4 @@ -'use strict' +"use strict" // global/public, for debugging/testing purposes /*exported RGBDR_anim*/ const RGBDR_anim = (() => { @@ -62,9 +62,9 @@ const RGBDR_anim = (() => { doc = document, body = doc.body, RAF = requestAnimationFrame, - canv = /**@type {HTMLCanvasElement}*/(doc.getElementById('c')), + canv = /**@type {HTMLCanvasElement}*/(doc.getElementById("c")), ctx = /**@type {CanvasRenderingContext2D}*/( - canv.getContext('2d', { alpha: false, desynchronized: true }) + canv.getContext("2d", { alpha: false, desynchronized: true }) ) let @@ -78,12 +78,12 @@ const RGBDR_anim = (() => { @param {string} color hex without "#" */ const ctx_fillFull = color => { - ctx.fillStyle = '#' + color + ctx.fillStyle = "#" + color ctx.fillRect(0, 0, w, h) // should it preserve the previous `fillStyle`? } - const light_query = matchMedia?.('(prefers-color-scheme: light)') + const light_query = matchMedia?.("(prefers-color-scheme: light)") // dark must act as default, so light is optional let is_dark = !light_query?.matches @@ -115,16 +115,16 @@ const RGBDR_anim = (() => { */ settings: { /** hex */ - colors: ['f00', 'ff0', '0f0', '0ff', '00f', 'f0f'],//🌈RYGCBM + colors: ["f00", "ff0", "0f0", "0ff", "00f", "f0f"],//🌈RYGCBM /** character-set/alphabet. must only contain codepoints, not grapheme-clusters, because the latter can be rendered at any size. */ charset: - [...('0123456789' + - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + - 'abcdefghijklmnopqrstuvwxyz')], + [...("0123456789" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz")], /** droplet falling speed */ droplet_Hz: 24, /** ratio to multiply with canvas dimensions */ @@ -167,7 +167,7 @@ const RGBDR_anim = (() => { this.#max_y = MAX_U8 // visible in light and dark schemes, // for easier debugging - this.#color = '777' + this.#color = "777" } /** @@ -225,8 +225,8 @@ const RGBDR_anim = (() => { */ const resize = () => { const { clientWidth, clientHeight } = body - canv.style.width = clientWidth + 'px' - canv.style.height = clientHeight + 'px' + canv.style.width = clientWidth + "px" + canv.style.height = clientHeight + "px" const scale = devicePixelRatio w = canv.width = clientWidth * scale >>> 0 h = canv.height = clientHeight * scale >>> 0 @@ -288,7 +288,7 @@ const RGBDR_anim = (() => { for (const [i, d] of [...droplets_user].entries()) { // this is outside `for...of` // to take advantage of batch-rendering - ctx.fillStyle = '#' + d.color + ctx.fillStyle = "#" + d.color // unlock speed limit to go beyond FPS ⚡ for (const _ of range(steps)) { @@ -305,7 +305,7 @@ const RGBDR_anim = (() => { } // according to MDN, this is thread-safe for (const d of droplets_auto) { - ctx.fillStyle = '#' + d.color + ctx.fillStyle = "#" + d.color for (const _ of range(steps)) { draw_char(d.x, d.y) @@ -342,7 +342,7 @@ const RGBDR_anim = (() => { // performance [0]... if (dim) { //eslint-disable-next-line no-magic-numbers - ctx_fillFull((df < 0 ? 'ffffff' : '000000') + dim.toString(0x10).padStart(2, '0')) + ctx_fillFull((df < 0 ? "ffffff" : "000000") + dim.toString(0x10).padStart(2, "0")) // [0]... and ensure hi-FPS don't cause `dim` to get stuck as a no-op. last_dim = now } @@ -373,7 +373,7 @@ const RGBDR_anim = (() => { const main = () => { // not part of anim, and has some latency, so no RAF resize() - ctx_fillFull(anim.settings.dim_factor < 0 ? 'fff' : '000') + ctx_fillFull(anim.settings.dim_factor < 0 ? "fff" : "000") // these don't work as desired //ctx.textAlign = 'center' //ctx.textBaseline = 'middle' @@ -383,7 +383,7 @@ const RGBDR_anim = (() => { anim.playing = true - canv.addEventListener('click', e => { + canv.addEventListener("click", e => { const scale = devicePixelRatio droplets_user.push((new Droplet).init( e.clientX * scale, e.clientY * scale @@ -403,12 +403,12 @@ const RGBDR_anim = (() => { @type {undefined|number} */let tm_ID // should this be attached to `body` rather than `window`? - addEventListener('resize', () => { + addEventListener("resize", () => { clearTimeout(tm_ID) tm_ID = setTimeout(resize, anim.settings.resize_delay_ms) }) - light_query?.addEventListener?.('change', e => { + light_query?.addEventListener?.("change", e => { is_dark = !e.matches // can't use alias, because we need live version anim.settings.dim_factor = Math.abs(anim.settings.dim_factor) * (is_dark ? 1 : -1)