diff --git a/core/modules/widgets/scrollable.js b/core/modules/widgets/scrollable.js index f34d462e7..42705a61b 100644 --- a/core/modules/widgets/scrollable.js +++ b/core/modules/widgets/scrollable.js @@ -181,7 +181,7 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) { }; ScrollableWidget.prototype.listenerFunction = function(event) { - self = this; + var self = this; clearTimeout(this.timeout); this.timeout = setTimeout(function() { var existingTiddler = self.wiki.getTiddler(self.scrollableBind), diff --git a/editions/test/tiddlers/tests/test-checkbox-widget.js b/editions/test/tiddlers/tests/test-checkbox-widget.js index 83ed66421..52a71d0c0 100644 --- a/editions/test/tiddlers/tests/test-checkbox-widget.js +++ b/editions/test/tiddlers/tests/test-checkbox-widget.js @@ -103,7 +103,7 @@ Tests the checkbox widget thoroughly. ]; var indexModeTests = fieldModeTests.map(data => { - var newData = {...data}; + var newData = Object.assign({}, data); var newName = data.testName.replace('field mode', 'index mode'); var tiddlerOneAlreadyExists = false; var newTiddlers = data.tiddlers.map(tiddler => { @@ -274,14 +274,13 @@ Tests the checkbox widget thoroughly. listModeTests .filter(data => data.widgetText.includes("listField='colors'")) .map(data => { - var newData = { - ...data, - tiddlers: data.tiddlers.map(tiddler => ({...tiddler, list: tiddler.colors, colors: undefined})), + var newData = Object.assign({}, data, { + tiddlers: data.tiddlers.map(tiddler => Object.assign({}, tiddler, {list: tiddler.colors, colors: undefined})), widgetText: data.widgetText.replace("listField='colors'", "listField='list'"), expectedChange: { "Colors": { list: data.expectedChange.Colors.colors.split(' ') } }, - } + }) return newData; }) ); @@ -289,20 +288,19 @@ Tests the checkbox widget thoroughly. listModeTests .filter(data => data.widgetText.includes("listField='colors'")) .map(data => { - var newData = { - ...data, - tiddlers: data.tiddlers.map(tiddler => ({...tiddler, tags: tiddler.colors, colors: undefined})), + var newData = Object.assign({}, data, { + tiddlers: data.tiddlers.map(tiddler => Object.assign({}, tiddler, {tags: tiddler.colors, colors: undefined})), widgetText: data.widgetText.replace("listField='colors'", "listField='tags'"), expectedChange: { "Colors": { tags: data.expectedChange.Colors.colors.split(' ') } }, - } + }) return newData; }) ); var indexListModeTests = listModeTests.map(data => { - var newData = {...data}; + var newData = Object.assign({}, data); var newName = data.testName.replace('list mode', 'index list mode'); var newTiddlers = data.tiddlers.map(tiddler => { if (tiddler.hasOwnProperty('colors')) { diff --git a/eslint.config.js b/eslint.config.mjs similarity index 83% rename from eslint.config.js rename to eslint.config.mjs index 2b05f7b0f..d29d27569 100644 --- a/eslint.config.js +++ b/eslint.config.mjs @@ -1,17 +1,39 @@ -const globals = require("globals"); -const js = require("@eslint/js"); +//@ts-check +// const globals = require("globals"); +// /** @type {import("@eslint/js")} */ +// const js = require("@eslint/js"); +// /** @type {import("eslint")} */ +// const eslint = require("eslint"); +// const { FlatCompat, } = require("@eslint/eslintrc"); +// const { fixupConfigRules } = require("@eslint/compat"); +import { defineConfig } from "eslint/config"; +import globals from "globals"; +import js from "@eslint/js"; +import eslint from "eslint"; +import { FlatCompat } from "@eslint/eslintrc"; +import { fixupConfigRules } from "@eslint/compat"; +import esx from "eslint-plugin-es-x" -const { - FlatCompat, -} = require("@eslint/eslintrc"); +/** @type {import("eslint").Linter.Config} */ +const es2017rules = { + //@ts-ignore + plugins: esx.configs["flat/restrict-to-es2017"].plugins, + //@ts-ignore + rules: esx.configs["flat/restrict-to-es2017"].rules, + ignores: ["bin/**/*", "core-server/**/*"], +}; +/** @type {import("eslint").Linter.Config} */ +const es2023rules = { + //@ts-ignore + plugins: esx.configs["flat/restrict-to-es2023"].plugins, + //@ts-ignore + rules: esx.configs["flat/restrict-to-es2023"].rules, + files: ["bin/**/*", "core-server/**/*"], +}; -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all -}); -module.exports = [{ + +export default defineConfig([{ ignores: [ // Ignore "third party" code whose style we will not change. "boot/sjcl.js", @@ -21,17 +43,15 @@ module.exports = [{ "core/modules/utils/diff-match-patch/diff_match_patch_uncompressed.js", "core/modules/utils/dom/csscolorparser.js", "plugins/tiddlywiki/*/files/", + "eslint.config.mjs", + "playwright.config.js", ], -}, ...compat.extends("eslint:recommended"), { - languageOptions: { - globals: { - ...globals.browser, - ...globals.commonjs, - ...globals.node, - $tw: "writable", // temporary - }, - ecmaVersion: 5, +}, +js.configs.recommended, +{ + languageOptions: { + ecmaVersion: "latest", sourceType: "commonjs", }, @@ -42,12 +62,10 @@ module.exports = [{ "array-element-newline": "off", "arrow-body-style": "error", "arrow-parens": ["error", "as-needed"], - "arrow-spacing": ["error", { after: true, before: true, }], - "block-scoped-var": "off", "block-spacing": "off", "brace-style": "off", @@ -91,38 +109,18 @@ module.exports = [{ "init-declarations": "off", "jsx-quotes": "error", "key-spacing": "off", - "keyword-spacing": ["error", { before: true, after: false, - overrides: { - case: { - after: true, - }, - - do: { - after: true, - }, - - else: { - after: true, - }, - - return: { - after: true, - }, - - throw: { - after: true, - }, - - try: { - after: true, - }, + case: { after: true }, + do: { after: true }, + else: { after: true }, + return: { after: true }, + throw: { after: true }, + try: { after: true }, }, }], - "line-comment-position": "off", "linebreak-style": "off", "lines-around-comment": "off", @@ -152,11 +150,7 @@ module.exports = [{ "no-catch-shadow": "off", "no-confusing-arrow": "error", "no-console": "off", - - "no-constant-condition": ["error", { - checkLoops: false, - }], - + "no-constant-condition": ["error", { checkLoops: false }], "no-constructor-return": "error", "no-continue": "off", "no-div-regex": "off", @@ -170,13 +164,11 @@ module.exports = [{ "no-extra-label": "off", "no-extra-parens": "off", "no-floating-decimal": "off", - "no-implicit-coercion": ["error", { boolean: false, number: false, string: false, }], - "no-implicit-globals": "off", "no-implied-eval": "error", "no-inline-comments": "off", @@ -213,13 +205,13 @@ module.exports = [{ "no-promise-executor-return": "error", "no-proto": "off", "no-restricted-exports": "error", - "no-restricted-globals": "error", + "no-restricted-globals": ["error", "self"], "no-restricted-imports": "error", "no-restricted-modules": "error", "no-restricted-properties": "error", "no-restricted-syntax": "error", "no-return-assign": "off", - "no-return-await": "error", + "no-return-await": "off", "no-script-url": "off", "no-self-compare": "off", "no-sequences": "off", @@ -275,11 +267,7 @@ module.exports = [{ "prefer-spread": "off", "prefer-template": "off", "quote-props": "off", - - quotes: ["error", "double", { - avoidEscape: true, - }], - + quotes: ["error", "double", { avoidEscape: true }], radix: "off", "require-atomic-updates": "error", "require-await": "error", @@ -305,17 +293,12 @@ module.exports = [{ "template-tag-spacing": "error", "unicode-bom": ["error", "never"], "valid-jsdoc": "off", - - "valid-typeof": ["error", { - requireStringLiterals: false, - }], - + "valid-typeof": ["error", { requireStringLiterals: false }], "vars-on-top": "off", "wrap-iife": "off", "wrap-regex": "off", "yield-star-spacing": "error", yoda: "off", - // temporary rules "no-useless-escape": "off", "no-unused-vars": "off", @@ -330,4 +313,8 @@ module.exports = [{ "no-unreachable": "off", "no-self-assign": "off", }, -}]; \ No newline at end of file + +}, + es2017rules, + es2023rules +]); \ No newline at end of file diff --git a/package.json b/package.json index fb499d299..f9702b0b5 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,11 @@ "wiki" ], "devDependencies": { - "eslint": "^9.12.0", - "@eslint/js": "^9.12.0" + "@eslint/compat": "1.4.0", + "@eslint/js": "9.36.0", + "eslint": "9.36.0", + "eslint-plugin-es-x": "9.1.0", + "globals": "16.4.0" }, "bundleDependencies": [], "license": "BSD", @@ -35,7 +38,8 @@ "scripts": { "dev": "node ./tiddlywiki.js ./editions/tw5.com-server --listen", "test": "node ./tiddlywiki.js ./editions/test --verbose --version --build index", + "lint": "eslint .", "lint:fix": "eslint . --fix", - "lint": "eslint ." + "lint:check": "eslint . --fix-dry-run" } } diff --git a/plugins/tiddlywiki/googleanalytics/googleanalytics.js b/plugins/tiddlywiki/googleanalytics/googleanalytics.js index 4dfbb1ef5..1cb751e51 100644 --- a/plugins/tiddlywiki/googleanalytics/googleanalytics.js +++ b/plugins/tiddlywiki/googleanalytics/googleanalytics.js @@ -25,7 +25,7 @@ exports.startup = function() { var gaMeasurementID = $tw.wiki.getTiddlerText("$:/GoogleAnalyticsMeasurementID","").replace(/\n/g,""); var url ="https://www.googletagmanager.com/gtag/js?id=" + gaMeasurementID; window.dataLayer = window.dataLayer || []; - window.gtag = function() { window.dataLayer?.push(arguments); }; + window.gtag = function() { if(window.dataLayer) window.dataLayer.push(arguments); }; window.gtag("js",new Date()); window.gtag("config",gaMeasurementID); const scriptElement = window.document.createElement("script"); diff --git a/plugins/tiddlywiki/twitter-archivist/archivist.js b/plugins/tiddlywiki/twitter-archivist/archivist.js index 69b7e8153..a3f40fc51 100644 --- a/plugins/tiddlywiki/twitter-archivist/archivist.js +++ b/plugins/tiddlywiki/twitter-archivist/archivist.js @@ -7,6 +7,8 @@ Utility class for manipulating Twitter archives \*/ +/* eslint-disable no-await-in-loop */ +/* eslint-disable require-await */ "use strict"; function TwitterArchivist(options) { @@ -228,13 +230,22 @@ TwitterArchivistSourceBrowser.prototype.init = async function() { TwitterArchivistSourceBrowser.prototype.processFiles = async function(dirPath,encoding,callback) { const dirHandle = await this.walkDirectory(dirPath.split("/")); - for await (const [filename, fileHandle] of dirHandle.entries()) { + const asyncIterator = dirHandle.entries(); + await AsyncIteratorForEach(asyncIterator, async ([filename, fileHandle]) => { const contents = await fileHandle.getFile(); callback({ filename: filename, - contents: arrayBufferToBase64(await contents.arrayBuffer()) + contents: encoding === "base64" ? arrayBufferToBase64(await contents.arrayBuffer()) : await contents.text() }); - } + }); + + // for await (const [filename, fileHandle] of dirHandle.entries()) { + // const contents = await fileHandle.getFile(); + // callback({ + // filename: filename, + // contents: arrayBufferToBase64(await contents.arrayBuffer()) + // }); + // } }; TwitterArchivistSourceBrowser.prototype.loadTwitterJsData = async function(filePath) { @@ -309,6 +320,26 @@ function arrayBufferToBase64(arrayBuffer) { return base64; } + +async function AsyncIteratorForEach(iter, callback) { + + // Start the iteration + try { + while(true) { + // Await the next result object + const { value, done } = await iter.next(); + if(done) break; + await callback(value); + } + } finally { + // If the iterator supports cleanup, call it + if(typeof iter.return === "function") { + await iter.return(); + } + } +} + + exports.TwitterArchivist = TwitterArchivist; exports.TwitterArchivistSourceNodeJs = TwitterArchivistSourceNodeJs; exports.TwitterArchivistSourceBrowser = TwitterArchivistSourceBrowser; diff --git a/plugins/tiddlywiki/xlsx-utils/importer.js b/plugins/tiddlywiki/xlsx-utils/importer.js index f20f0a691..fd8ed7526 100644 --- a/plugins/tiddlywiki/xlsx-utils/importer.js +++ b/plugins/tiddlywiki/xlsx-utils/importer.js @@ -144,7 +144,7 @@ XLSXImporter.prototype.processField = function(fieldImportSpecTitle) { value = cell.v.toString(); break; case "string": - // Intentional fall-through + // falls through default: value = cell.w; break;