From b0d84eab63fbb8b3692d9363dd8cab32559fa467 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Tue, 15 Oct 2024 08:02:56 -0700 Subject: [PATCH] 0.6.13 - Removed `xregexp` and `html-entities` dependencies. Also Replaced `cheerio` with `cheerio/slim`. These changes have reduced bundle size significantly. - Began work on `cheerioPolyfill.js` which will allow Teddy to execute in client-side contexts without using `cheerio`. This will result in even smaller bundle sizes (currently around 16kb minified), however the work is unfinished. - Updated various dependencies. --- CHANGELOG.md | 6 + cheerioPolyfill.js | 87 ++++++ package-lock.json | 548 ++++++++++++++++++++----------------- package.json | 16 +- teddy.js | 98 ++++++- test/loaders/playwright.js | 3 +- test/tests.js | 9 +- webpack.config.js | 255 +++++++++++++++-- 8 files changed, 722 insertions(+), 300 deletions(-) create mode 100644 cheerioPolyfill.js diff --git a/CHANGELOG.md b/CHANGELOG.md index fe11b97..d97cd28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ - Put your changes here... +## 0.6.13 + +- Removed `xregexp` and `html-entities` dependencies. Also Replaced `cheerio` with `cheerio/slim`. These changes have reduced bundle size significantly. +- Began work on `cheerioPolyfill.js` which will allow Teddy to execute in client-side contexts without using `cheerio`. This will result in even smaller bundle sizes (currently around 16kb minified), however the work is unfinished. +- Updated various dependencies. + ## 0.6.12 - Downgraded `cheerio` to prevent webpack errors when using Teddy on frontend. diff --git a/cheerioPolyfill.js b/cheerioPolyfill.js new file mode 100644 index 0000000..9bc90ee --- /dev/null +++ b/cheerioPolyfill.js @@ -0,0 +1,87 @@ +// extend HTMLElement prototype to include cheerio properties +Object.defineProperty(window.HTMLElement.prototype, 'attribs', { + get: function () { + if (this.__attribs === undefined) this.__attribs = this.attributes + return this.__attribs + } +}) + +Object.defineProperty(window.HTMLElement.prototype, 'name', { + get: function () { + if (this.__name === undefined) this.__name = this.nodeName.toLowerCase() + return this.__name + } +}) + +Object.defineProperty(window.HTMLElement.prototype, 'parent', { + get: function () { + if (this.__parent === undefined) this.__parent = this.parentNode + return this.__parent + } +}) + +// TODO: write more HTMLElement property extensions to polyfill cheerio: this will require reading teddy.js line by line to see what properties from cheerio each method uses and adapt them like above one property at a time + +// create a native DOMParser +const parser = new window.DOMParser() + +// stub out cheerio using native dom methods for frontend so we don't have to bundle cheerio on the frontend +export function load (html) { + console.log('Loading cheerio polyfill... TODO: This is unfinished! Please use teddy.mjs or teddy.cjs via a bundle for now.') + const doc = parser.parseFromString(html, 'text/html') + + // return a querySelector function with function chains + // e.g. dom('include') or dom(el) from teddy + const $ = function (query) { // query can be a string, or a dom object + // if query is a string, we need to create a dom object from the string: an object with elements in it, e.g. a list of include tag objects + if (typeof query === 'string') { + const els = doc.querySelectorAll(query) + console.log(els) + return els // return the object collection + } + + // if query is an object, it's assumed we're trying to perform operations on a single dom node + const el = query + return { + + // e.g. dom(el).children() from teddy + children: function () { + return el.children + }, + + // e.g. dom(arg).html() from teddy + html: function () { + return el.innerHTML + }, + + // e.g. dom(el).attr('teddy_deferred_dynamic_include', 'true') from teddy + attr: function (attr, val) { + return el.setAttribute(attr, val) + }, + + // dom(el).removeAttr(attr) from teddy + removeAttr: function (attr) { + return el.removeAttribute(attr) + }, + + // e.g. dom(el).replaceWith(localDom.html()) from teddy + replaceWith: function (html) { + const temp = document.createElement('div') + temp.innerHTML = html + el.replaceWith(...temp.children) + }, + + // e.g. dom(el).remove() from teddy + remove: function () { + return el.remove() + } + } + } + + // e.g. dom.html() from teddy + $.html = function () { + return doc.body.innerHTML + } + + return $ +} diff --git a/package-lock.json b/package-lock.json index ab065fe..aa2b5df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,30 +1,28 @@ { "name": "teddy", - "version": "0.6.12", + "version": "0.6.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "teddy", - "version": "0.6.12", + "version": "0.6.13", "license": "CC-BY-4.0", "dependencies": { - "cheerio": "1.0.0-rc.12", - "html-entities": "2.5.2", - "xregexp": "5.1.1" + "cheerio": "1.0.0" }, "devDependencies": { - "@playwright/test": "1.47.2", + "@playwright/test": "1.48.0", "c8": "10.1.2", "codecov": "3.8.3", "cross-env": "7.0.3", - "eslint": "9.11.0", - "eslint-plugin-html": "8.1.1", + "eslint": "9.12.0", + "eslint-plugin-html": "8.1.2", "eslint-plugin-mocha": "10.5.0", "mocha": "10.7.3", "standard": "17.1.2", "terser-webpack-plugin": "5.3.10", - "webpack": "5.94.0", + "webpack": "5.95.0", "webpack-cli": "5.1.4" }, "engines": { @@ -34,19 +32,6 @@ "url": "https://www.paypal.com/donate/?hosted_button_id=2L2X8GRXZCGJ6" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.6.tgz", - "integrity": "sha512-Gz0Nrobx8szge6kQQ5Z5MX9L3ObqNwCQY1PSwSNzreFL7aHGxv8Fp2j3ETV6/wWdbiV+mW6OSm8oQhg3Tcsniw==", - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -118,6 +103,16 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -163,9 +158,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.0.tgz", - "integrity": "sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, "license": "MIT", "engines": { @@ -195,6 +190,30 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -234,9 +253,9 @@ "license": "BSD-3-Clause" }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -474,13 +493,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.2.tgz", - "integrity": "sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.0.tgz", + "integrity": "sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.47.2" + "playwright": "1.48.0" }, "bin": { "playwright": "cli.js" @@ -535,9 +554,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.5.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", - "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1148,9 +1167,9 @@ "license": "ISC" }, "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -1168,8 +1187,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, @@ -1275,9 +1294,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001662", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz", - "integrity": "sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA==", + "version": "1.0.30001668", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz", + "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==", "dev": true, "funding": [ { @@ -1313,21 +1332,25 @@ } }, "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=18.17" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -1497,17 +1520,6 @@ "dev": true, "license": "MIT" }, - "node_modules/core-js-pure": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.1.tgz", - "integrity": "sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -1784,9 +1796,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.27", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz", - "integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==", + "version": "1.5.38", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.38.tgz", + "integrity": "sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg==", "dev": true, "license": "ISC" }, @@ -1797,6 +1809,19 @@ "dev": true, "license": "MIT" }, + "node_modules/encoding-sniffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", + "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -1931,9 +1956,9 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", "dev": true, "license": "MIT", "dependencies": { @@ -1944,12 +1969,12 @@ "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", + "iterator.prototype": "^1.1.3", "safe-array-concat": "^1.1.2" }, "engines": { @@ -2043,29 +2068,32 @@ } }, "node_modules/eslint": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.0.tgz", - "integrity": "sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", + "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.11.0", + "@eslint/js": "9.12.0", "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2075,13 +2103,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { @@ -2125,9 +2151,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz", - "integrity": "sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, "license": "MIT", "dependencies": { @@ -2199,9 +2225,9 @@ } }, "node_modules/eslint-plugin-html": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-8.1.1.tgz", - "integrity": "sha512-6qmlJsc40D2m3Dn9oEH+0PAOkJhxVu0f5sVItqpCE0YWgYnyP4xCjBc3UWTHaJcY9ARkWOLIIuXLq0ndRnQOHw==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-8.1.2.tgz", + "integrity": "sha512-pbRchDV2SmqbCi/Ev/q3aAikzG9BcFe0IjjqjtMn8eTLq71ZUggyJB6CDmuwGAXmYZHrXI12XTfCqvgcnPRqGw==", "dev": true, "license": "ISC", "dependencies": { @@ -2211,24 +2237,58 @@ "node": ">=16.0.0" } }, - "node_modules/eslint-plugin-html/node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], "license": "MIT", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/eslint-plugin-mocha": { @@ -2321,9 +2381,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.36.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", - "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", + "version": "7.37.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", + "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", "dev": true, "license": "MIT", "dependencies": { @@ -2382,9 +2442,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -2428,9 +2488,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2441,15 +2501,15 @@ } }, "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3028,22 +3088,6 @@ "he": "bin/he" } }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -3052,9 +3096,9 @@ "license": "MIT" }, "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -3066,8 +3110,8 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" + "domutils": "^3.1.0", + "entities": "^4.5.0" } }, "node_modules/http-proxy-agent": { @@ -3099,6 +3143,18 @@ "node": ">= 6" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3715,9 +3771,9 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3726,6 +3782,9 @@ "has-symbols": "^1.0.3", "reflect.getprototypeof": "^1.0.4", "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/jackspeak": { @@ -4457,9 +4516,9 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, @@ -4491,24 +4550,36 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz", + "integrity": "sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA==", "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" } }, "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", "license": "MIT", "dependencies": { - "domhandler": "^5.0.2", "parse5": "^7.0.0" }, "funding": { @@ -4749,13 +4820,13 @@ } }, "node_modules/playwright": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz", - "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.0.tgz", + "integrity": "sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.47.2" + "playwright-core": "1.48.0" }, "bin": { "playwright": "cli.js" @@ -4768,9 +4839,9 @@ } }, "node_modules/playwright-core": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz", - "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.0.tgz", + "integrity": "sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4930,23 +5001,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -5161,6 +5226,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -5442,10 +5513,24 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/standard/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/standard/node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { @@ -5553,49 +5638,6 @@ "eslint-plugin-react": "^7.28.0" } }, - "node_modules/standard/node_modules/eslint-plugin-import": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", - "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.9.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/standard/node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/standard/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -5626,19 +5668,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/standard/node_modules/eslint/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/standard/node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -5714,16 +5743,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/standard/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/standard/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -5979,9 +5998,9 @@ } }, "node_modules/terser": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz", - "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==", + "version": "5.34.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", + "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6250,6 +6269,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.20.1.tgz", + "integrity": "sha512-AjQF1QsmqfJys+LXfGTNum+qw4S88CojRInG/6t31W/1fk6G59s92bnAvGz5Cmur+kQv2SURXEvvudLmbrE8QA==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", @@ -6258,9 +6286,9 @@ "license": "MIT" }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -6278,8 +6306,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -6365,9 +6393,9 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.94.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", - "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "dev": true, "license": "MIT", "dependencies": { @@ -6516,6 +6544,27 @@ "node": ">=4.0" } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -6704,15 +6753,6 @@ "node": ">=8" } }, - "node_modules/xregexp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.1.tgz", - "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", - "license": "MIT", - "dependencies": { - "@babel/runtime-corejs3": "^7.16.5" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 74ebf5d..74288ce 100644 --- a/package.json +++ b/package.json @@ -8,14 +8,14 @@ "url": "https://github.com/rooseveltframework/teddy/graphs/contributors" } ], - "version": "0.6.12", + "version": "0.6.13", "files": [ "dist" ], "type": "module", "exports": { ".": { - "import": "./dist/teddy.js", + "import": "./dist/teddy.mjs", "require": "./dist/teddy.cjs" } }, @@ -27,22 +27,20 @@ "node": ">=18.0.0" }, "dependencies": { - "cheerio": "1.0.0-rc.12", - "html-entities": "2.5.2", - "xregexp": "5.1.1" + "cheerio": "1.0.0" }, "devDependencies": { - "@playwright/test": "1.47.2", + "@playwright/test": "1.48.0", "c8": "10.1.2", "codecov": "3.8.3", "cross-env": "7.0.3", - "eslint": "9.11.0", - "eslint-plugin-html": "8.1.1", + "eslint": "9.12.0", + "eslint-plugin-html": "8.1.2", "eslint-plugin-mocha": "10.5.0", "mocha": "10.7.3", "standard": "17.1.2", "terser-webpack-plugin": "5.3.10", - "webpack": "5.94.0", + "webpack": "5.95.0", "webpack-cli": "5.1.4" }, "standard": { diff --git a/teddy.js b/teddy.js index e204c41..d7ae774 100644 --- a/teddy.js +++ b/teddy.js @@ -2,12 +2,8 @@ import fs from 'fs' // node filesystem module import path from 'path' // node path module -import { load as cheerioLoad } from 'cheerio' // dom parser -import XRegExp from 'xregexp/lib/index.js' // needed for matchRecursive -import matchRecursiveModule from 'xregexp/lib/addons/matchrecursive.js' // include matchRecursive addon -import htmlEntities from 'html-entities' // escapes sensitive characters to prevent xss +import { load as cheerioLoad } from 'cheerio/slim' // dom parser -matchRecursiveModule(XRegExp) // load matchRecursive addon into XRegExp const cheerioOptions = { xml: { xmlMode: false, lowerCaseAttributeNames: false, decodeEntities: false } } const params = {} // teddy parameters setDefaultParams() // set params to the defaults @@ -81,7 +77,7 @@ function removeTeddyComments (renderedTemplate) { oldTemplate = renderedTemplate let vars try { - vars = XRegExp.matchRecursive(renderedTemplate, '{!', '!}', 'g') + vars = matchByDelimiter(renderedTemplate, '{!', '!}') } catch (e) { return renderedTemplate // it will match {! comments {! with comments in them !} !} but if there are unbalanced brackets, just return the original text } @@ -261,7 +257,7 @@ function parseConditionals (dom, model) { nextSibling = nextSibling.nextSibling } } - removeStack.forEach((element) => dom(element).replaceWith('')) + for (const element of removeStack) dom(element).replaceWith('') dom(el).replaceWith(el.children) parsedTags++ } else { @@ -299,7 +295,7 @@ function parseConditionals (dom, model) { nextSibling = nextSibling.nextSibling } } - removeStack.forEach((element) => dom(element).replaceWith('')) + for (const element of removeStack) dom(element).replaceWith('') nextSibling = false parsedTags++ } else { @@ -339,7 +335,7 @@ function parseConditionals (dom, model) { nextSibling = nextSibling.nextSibling } } - removeStack.forEach((element) => dom(element).replaceWith('')) + for (const element of removeStack) dom(element).replaceWith('') nextSibling = false parsedTags++ } else { @@ -586,7 +582,7 @@ function parseLoops (dom, model) { function parseVars (templateString, model) { let vars try { - vars = XRegExp.matchRecursive(templateString, '{', '}', 'g') + vars = matchByDelimiter(templateString, '{', '}') } catch (e) { return templateString // it will match {vars{withVarsInThem}} but if there are unbalanced brackets, just return the original text } @@ -642,7 +638,7 @@ function parseVars (templateString, model) { // no flags are set let parsed = getOrSetObjectByDotNotation(model, match) if (params.emptyVarBehavior === 'hide' && !parsed) parsed = '' // display empty string instead of the variable text verbatim if this setting is set - else if (parsed || parsed === '') parsed = htmlEntities.encode(parsed) + else if (parsed || parsed === '') parsed = escapeEntities(parsed) else if (parsed === 0) parsed = '0' else parsed = `{${match}}` try { @@ -718,6 +714,86 @@ function cleanupStrayTeddyTags (dom) { return dom } +// escapes sensitive characters to prevent xss +const escapeHtmlEntities = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' +} +const entityKeys = Object.keys(escapeHtmlEntities) +const ekl = entityKeys.length +function escapeEntities (value) { + let escapedEntity = false + let newValue = '' + let i + let j + + if (typeof value === 'object') { // cannot escape on this value + if (!value) return false // it is falsey to return false + else if (Array.isArray(value)) { + if (value.length === 0) return false // empty arrays are falsey + else return '[Array]' // print that it is an array with content in it, but do not print the contents + } + return '[Object]' // just print that it is an object, do not print the contents + } else if (value === undefined) return false // cannot escape on this value; undefined is falsey + else if (typeof value === 'boolean' || typeof value === 'number') return value // cannot escape on these values; if it's already a boolean or a number just return it + else { + // loop through value to find html entities + for (i = 0; i < value.length; i++) { + escapedEntity = false + + // loop through list of html entities to escape + for (j = 0; j < ekl; j++) { + if (value[i] === entityKeys[j]) { // alter value to show escaped html entities + newValue += escapeHtmlEntities[entityKeys[j]] + escapedEntity = true + break + } + } + + if (!escapedEntity) newValue += value[i] + } + } + + return newValue +} + +// match strings by a custom delimiter +function matchByDelimiter (input, openDelimiter, closeDelimiter) { + const stack = [] + const result = [] + const openLength = openDelimiter.length + const closeLength = closeDelimiter.length + + for (let i = 0; i < input.length; i++) { + if (input.substring(i, i + openLength) === openDelimiter) { + stack.push(i + openLength) + i += openLength - 1 + } else if (input.substring(i, i + closeLength) === closeDelimiter) { + const start = stack.pop() + if (stack.length === 0) { + result.push(input.substring(start, i)) + } + i += closeLength - 1 + } + } + + const individualSegments = [] + const regex = /{!([^{}]*)!}/g + let match + + for (const segment of result) { + while ((match = regex.exec(segment)) !== null) { + individualSegments.push(match[1]) + } + individualSegments.push(segment) + } + + return individualSegments +} + // gets or sets an object by dot notation, e.g. thing.nestedThing.furtherNestedThing: two arguments gets, three arguments sets function getOrSetObjectByDotNotation (obj, dotNotation, value) { if (!obj) return false diff --git a/test/loaders/playwright.js b/test/loaders/playwright.js index abc34ac..21f2608 100644 --- a/test/loaders/playwright.js +++ b/test/loaders/playwright.js @@ -4,7 +4,8 @@ import testConditions from '../tests.js' import { ignoreSpaces } from '../testUtils.js' import { sanitizeTests, registerTemplates } from './loaderUtils.js' import teddy from '../../teddy.js' -// import fs from 'fs' + +// TODO: refactor this loader to import teddy from within the page's DOM so we can import the version of teddy without cheerio const conditions = sanitizeTests(testConditions) diff --git a/test/tests.js b/test/tests.js index 1199590..0038a20 100644 --- a/test/tests.js +++ b/test/tests.js @@ -1640,10 +1640,10 @@ export default [ }, { - describe: 'Client tests', + describe: 'Bundler tests', tests: [ { - message: 'should be able to be required', + message: 'should be able require teddy.cjs', type: 'custom', test: async (_params, _page, _model, assert) => { if (fs.existsSync('test/client.cjs')) fs.rmSync('test/client.cjs') @@ -1658,12 +1658,12 @@ export default [ expected: '' }, { - message: 'should be able to be imported', + message: 'should be able to import teddy.mjs', type: 'custom', test: (_params, _page, _model, assert) => { if (fs.existsSync('test/client.js')) fs.rmSync('test/client.js') - fs.writeFileSync('test/client.js', 'import teddy from "../dist/teddy.js"\nconsole.log(teddy)') + fs.writeFileSync('test/client.js', 'import teddy from "../dist/teddy.mjs"\nconsole.log(teddy)') const output = execSync('node ./test/client.js', { encoding: 'utf-8' }).toString() assert(output.includes('emptyVarBehavior:')) @@ -1672,6 +1672,7 @@ export default [ }, expected: '' } + // TODO: write bundler tests for client-side files that are exclusive to the playwright environent where the window variable is present ] } ] diff --git a/webpack.config.js b/webpack.config.js index c37c856..76350e7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,25 +6,117 @@ const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) export default [ - // import + + // #region server-side (cheerio-driven) versions of teddy + + // esm server-side (cheerio-driven) { name: 'main', entry: './teddy.js', + output: { + path: path.join(__dirname, 'dist'), + filename: 'teddy.mjs', + library: { + type: 'module' + } + }, + experiments: { + outputModule: true + }, + mode: 'development', + devtool: 'source-map', + optimization: { + minimize: true, + minimizer: [ + new TerserPlugin({ + extractComments: false, + terserOptions: { + compress: { + defaults: false, + unused: true + }, + mangle: false, + format: { + comments: 'all' + } + } + }) + ] + }, resolve: { fallback: { fs: false, path: false } + } + }, + + // commonjs server-side (cheerio-driven) + { + name: 'main', + entry: './teddy.js', + output: { + path: path.join(__dirname, 'dist'), + filename: 'teddy.cjs', + library: { + name: 'teddy', + type: 'umd', + export: 'default' + }, + globalObject: 'this', + umdNamedDefine: true }, + target: 'node', + mode: 'development', devtool: 'source-map', + optimization: { + minimize: true, + minimizer: [ + new TerserPlugin({ + extractComments: false, + terserOptions: { + compress: { + defaults: false, + unused: true + }, + mangle: false, + format: { + comments: 'all' + } + } + }) + ] + }, + resolve: { + fallback: { + fs: false, + path: false + } + } + }, + + // #endregion + + // #region client-side (not cheerio-driven) versions of teddy + + // esm client-side (not cheerio-driven) + { + name: 'main', + entry: './teddy.js', output: { path: path.join(__dirname, 'dist'), - filename: 'teddy.js', + filename: 'teddy.client.mjs', library: { type: 'module' - } + }, + globalObject: 'this', + umdNamedDefine: true + }, + experiments: { + outputModule: true }, mode: 'development', + devtool: 'source-map', optimization: { minimize: true, minimizer: [ @@ -43,18 +135,24 @@ export default [ }) ] }, - experiments: { - outputModule: true + resolve: { + fallback: { + fs: false, + path: false + }, + alias: { + 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') + } } }, - // require + + // commonjs client-side (not cheerio-driven) { name: 'main', entry: './teddy.js', - devtool: 'source-map', output: { path: path.join(__dirname, 'dist'), - filename: 'teddy.cjs', + filename: 'teddy.client.cjs', library: { name: 'teddy', type: 'umd', @@ -63,8 +161,8 @@ export default [ globalObject: 'this', umdNamedDefine: true }, - target: 'node', mode: 'development', + devtool: 'source-map', optimization: { minimize: true, minimizer: [ @@ -82,27 +180,84 @@ export default [ } }) ] + }, + resolve: { + fallback: { + fs: false, + path: false + }, + alias: { + 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') + } } }, - // import -- production + + // standalone (directly includable in a