From f19ab51f12ef499aa975aaa36fa246a2492bbb25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 05:51:18 +0200 Subject: [PATCH 01/17] Lazy loaded translations + safe wrapper events attaching - translations are now copied to the direction `translations` in the destination, and the translations are not compiled with the main script - updated dev and prod build - updated help text for field `Locales` in the GTM template - added safe wrapper events attaching via window variable `window.cookieConsentWrapperEvents` - updated docs --- README.md | 45 +- build/.gitignore | 3 +- build/index.html | 189 +++---- docs/images/locale-options.png | Bin 0 -> 123005 bytes gtm_template.tpl | 2 +- package-lock.json | 758 +++++++++++++++++++++++------ package.json | 2 + src/CookieConsentWrapper.js | 34 +- src/CookieConsentWrapperFactory.js | 68 ++- src/Translation/Catalogue.js | 33 +- src/Translation/Dictionary.js | 18 +- webpack.config.dev.js | 17 +- webpack.config.prod.js | 22 +- 13 files changed, 901 insertions(+), 290 deletions(-) create mode 100644 docs/images/locale-options.png diff --git a/README.md b/README.md index f2806cf..2beb985 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,14 @@ The package comes with the default translations for the following languages: - [Ukrainian - uk](src/resources/translations/ua.json) Translations that will be loaded and accessible for the widget are taken from the field `Locales`. Each locale must be defined on a new line. -If you want to rewrite default translations or you want to add translations for a new locale then you can define them in a table `Translations`. +Alternatively, from version `1.0.0`, the URL from which the translations are to be downloaded can also be entered. + +Locale options + +In the example above, the default translations for the English language are downloaded and the translations for the German language are downloaded from the URL `https://www.example.com/public/cc-translations/de.json`. +A translation file must always be in JSON format and its name must match a locale. + +If you want to rewrite default translations, or you want to add translations for a new locale then you can define them in a table `Translations`. ### Locale detection @@ -268,7 +275,9 @@ And a tag that is fired with the trigger: ## Accessing the wrapper in the JavaScript The wrapper is accessible in the `window` under the name `CookieConsentWrapper`. The recommended way how to manipulate with it is through event callbacks because the wrapper may not be fully initialized at the time your script is executed. -Callbacks are attached with calling of the method `CookieConsentWrapper.on()`. +Callbacks are attached with calling of the method `CookieConsentWrapper.on()`, however since the version `1.0.0` the preferred method is to use the `window.cookieConsentWrapperEvents` variable. + +The use of the variable avoids the situation when the wrapper does not exist in the window yet. ### Init event @@ -276,13 +285,15 @@ A callback is invoked when the wrapper is fully initialized or directly if every ```html ``` @@ -290,15 +301,19 @@ A callback is invoked when the wrapper is fully initialized or directly if every ```html ``` @@ -306,10 +321,12 @@ A callback is invoked when the wrapper is fully initialized or directly if every ```html - + window.cc_wrapper_config = { + /*cmp_api_options: { + url: 'http://localhost:8888/', + project: 'demo', + consent_api_enabled: true, + cookies_api_enabled: true, + cookie_table_headers: ['name', 'purpose', 'processing_time', 'type', 'link', 'provider', 'category'], + }, + user_options: { + attributes: { + email: 'test@example.com', + }, + },*/ + plugin_options: { + cookie_name: 'consent-settings', + force_consent: true, + page_scripts: true, + }, + auto_clear_options: { + enabled: true, + strategy: 'clear_all_except_defined', + }, + consent_modal_options: { + position: 'middle center', + secondary_button_role: 'accept_necessary', + show_third_button: true, + }, + settings_modal_options: { + modal_trigger_selector: 'footer .footer-item', + }, + locales: [ + 'en', + ], + storage_pool: [ + { + name: 'functionality_storage', + enabled_by_default: true, + display_in_widget: true, + readonly: true, + }, + { + name: 'personalization_storage', + sync_consent_with: 'functionality_storage', + }, + { + name: 'security_storage', + display_in_widget: false, + }, + { + name: 'ad_storage', + display_in_widget: true + }, + { + name: 'analytics_storage', + display_in_widget: true + }, + ], + event_triggers: [ + { + name: 'functionality_storage_event', + storage_names: ['functionality_storage'], + type: 'or', + }, + { + name: 'personalization_storage_event', + storage_names: ['personalization_storage'], + type: 'or', + }, + { + name: 'security_storage_event', + storage_names: ['security_storage'], + type: 'or', + }, + { + name: 'ad_storage_event', + storage_names: ['ad_storage'], + type: 'or', + }, + { + name: 'analytics_storage_event', + storage_names: ['analytics_storage'], + type: 'or', + }, + { + name: 'fb_pixel_event', + storage_names: ['ad_storage', 'analytics_storage'], + type: 'and', + }, + ], + }; - + +
diff --git a/docs/images/locale-options.png b/docs/images/locale-options.png new file mode 100644 index 0000000000000000000000000000000000000000..8447c080a89e7b970ee8a6ab3b84c813e75c5444 GIT binary patch literal 123005 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 Nr!E*38QMSme*oj^gZKad literal 0 HcmV?d00001 diff --git a/gtm_template.tpl b/gtm_template.tpl index a679681..170a61f 100644 --- a/gtm_template.tpl +++ b/gtm_template.tpl @@ -1433,7 +1433,7 @@ ___TEMPLATE_PARAMETERS___ "type": "NON_EMPTY" } ], - "help": "One per line." + "help": "One locale per line. Alternatively, the URL from which the translations are to be downloaded can also be entered.\nFor example, \u003cstrong\u003ehttps://www.example.com/cc-translations/en.json\u003c/strong\u003e will download the file as an \u003cstrong\u003een\u003c/strong\u003e dictionary." }, { "type": "SELECT", diff --git a/package-lock.json b/package-lock.json index 8d57ebb..70899f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,8 @@ "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.16.4", "babel-loader": "^8.2.3", + "copy-webpack-plugin": "^12.0.2", + "json-minimizer-webpack-plugin": "^5.0.0", "path": "^0.12.7", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", @@ -40,13 +42,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -92,14 +94,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -203,34 +205,37 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -359,30 +364,30 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -426,23 +431,24 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1646,34 +1652,34 @@ "dev": true }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -1681,13 +1687,13 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1704,14 +1710,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1727,9 +1733,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1752,9 +1758,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1767,6 +1773,53 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@types/body-parser": { "version": "1.19.3", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", @@ -2378,13 +2431,13 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -2392,7 +2445,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -2448,12 +2501,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2507,13 +2560,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2730,9 +2789,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, "engines": { "node": ">= 0.6" @@ -2744,6 +2803,95 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", + "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/core-js": { "version": "2.6.12", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", @@ -2772,9 +2920,9 @@ "dev": true }, "node_modules/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "node_modules/debug": { "version": "4.3.4", @@ -2805,6 +2953,23 @@ "node": ">= 10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -2912,6 +3077,27 @@ "node": ">=4" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", @@ -3092,17 +3278,17 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -3160,6 +3346,22 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3175,6 +3377,15 @@ "node": ">= 4.9.1" } }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -3188,9 +3399,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -3263,9 +3474,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -3327,10 +3538,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -3342,15 +3556,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3415,6 +3633,38 @@ "node": ">=4" } }, + "node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3448,10 +3698,22 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -3472,6 +3734,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -3623,6 +3897,15 @@ "node": ">=0.10.0" } }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -3870,6 +4153,78 @@ "node": ">=4" } }, + "node_modules/json-minimizer-webpack-plugin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/json-minimizer-webpack-plugin/-/json-minimizer-webpack-plugin-5.0.0.tgz", + "integrity": "sha512-GT/SZolN2p405EMGjMTBvAVi2+y035p1tSOuLpWbp5QTMl080OHx4DEGXfUH6vbnGw5Z/QKfBe+KpP9Dj0qLmA==", + "dev": true, + "dependencies": { + "schema-utils": "^4.2.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/json-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/json-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/json-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -4011,6 +4366,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -4164,9 +4528,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4347,6 +4711,18 @@ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "dev": true }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4438,6 +4814,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -4457,9 +4853,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -4651,6 +5047,16 @@ "node": ">= 4" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -4666,6 +5072,29 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4783,9 +5212,9 @@ "dev": true }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -4878,6 +5307,23 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -4906,14 +5352,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4925,6 +5375,18 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -5204,6 +5666,18 @@ "node": ">=4" } }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -5474,9 +5948,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, "dependencies": { "colorette": "^2.0.10", @@ -5742,9 +6216,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index 30709bc..8c7ae2b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.16.4", "babel-loader": "^8.2.3", + "copy-webpack-plugin": "^12.0.2", + "json-minimizer-webpack-plugin": "^5.0.0", "path": "^0.12.7", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", diff --git a/src/CookieConsentWrapper.js b/src/CookieConsentWrapper.js index 0aaf8dd..7371f38 100644 --- a/src/CookieConsentWrapper.js +++ b/src/CookieConsentWrapper.js @@ -33,6 +33,14 @@ class CookieConsentWrapper { this._user = User.createDefault(); this._cookieConsent = null; + this._scriptBasePath = ''; + + if (document.currentScript && document.currentScript.src) { + const url = new URL(document.currentScript.src, window.location.origin); + const pathname = url.pathname.substring(0, url.pathname.lastIndexOf('/')); + + this._scriptBasePath = url.origin + pathname; + } } get version() { @@ -146,17 +154,21 @@ class CookieConsentWrapper { this._dictionary.addTranslations(locale, translations || {}); } - loadTranslations(locale) { - const localeIso639 = 2 < locale.length ? locale[0] + locale[1] : locale; - let translations; + loadTranslations(localeOrUrl, override = false) { + let url = null; + let locale = null; - try { - translations = require(`./resources/translations/${localeIso639}`); - } catch (e) { - translations = {}; + if (localeOrUrl.startsWith('https://') || localeOrUrl.startsWith('http://')) { + locale = localeOrUrl.split('/').pop().split('.').shift(); + locale = 2 < locale.length ? locale[0] + locale[1] : locale; + url = localeOrUrl; + } else { + locale = localeOrUrl; + locale = 2 < locale.length ? locale[0] + locale[1] : locale; + url = `${this._scriptBasePath}/translations/${locale}.json`; } - this.addTranslations(locale, translations); + return this._dictionary.loadTranslations(locale, url, override); } unwrap() { @@ -203,7 +215,7 @@ class CookieConsentWrapper { this._initializationTriggered = true; - const documentLoadedCallback = function () { + const documentLoadedCallback = async function () { // load stylesheets StylesheetLoader.loadFromConfig(document, self._config.uiOptions); @@ -218,7 +230,7 @@ class CookieConsentWrapper { config.onAccept = () => consentManager.onAccept(); config.onChange = (cookie, changedCategories) => consentManager.onChange(cookie, changedCategories); - config.languages = self._dictionary + config.languages = await self._dictionary .addPlaceholder('user_identity', self.user.identity.toString()) .exportTranslations(self._storagePool, self._config); @@ -256,7 +268,7 @@ class CookieConsentWrapper { }; if ('loading' !== document.readyState) { - documentLoadedCallback(); + void documentLoadedCallback(); } else { document.addEventListener('DOMContentLoaded', documentLoadedCallback); } diff --git a/src/CookieConsentWrapperFactory.js b/src/CookieConsentWrapperFactory.js index fc5911b..7c82a77 100644 --- a/src/CookieConsentWrapperFactory.js +++ b/src/CookieConsentWrapperFactory.js @@ -8,27 +8,45 @@ class CookieConsentWrapperFactory { throw new Error('the window is not accessible.'); } - const cookieConsentWrapper = new CookieConsentWrapper(this._createGtagFunction()); + const cookieConsentWrapper = new CookieConsentWrapper(this.#createGtagFunction()); const wrapperConfig = window.cc_wrapper_config || {}; - this._setupUser(cookieConsentWrapper, wrapperConfig); - this._setupPluginOptions(cookieConsentWrapper, wrapperConfig); - this._setupAutoClearOptions(cookieConsentWrapper, wrapperConfig); - this._setupConsentModalOptions(cookieConsentWrapper, wrapperConfig); - this._setupSettingsModalOptions(cookieConsentWrapper, wrapperConfig); - this._setupUiOptions(cookieConsentWrapper, wrapperConfig); - this._setupStoragePool(cookieConsentWrapper, wrapperConfig); - this._setupEventTriggers(cookieConsentWrapper, wrapperConfig); - this._setupLocales(cookieConsentWrapper, wrapperConfig); - this._setupTranslations(cookieConsentWrapper, wrapperConfig); - this._setupCmpApiOptions(cookieConsentWrapper, wrapperConfig); + this.#setupUser(cookieConsentWrapper, wrapperConfig); + this.#setupPluginOptions(cookieConsentWrapper, wrapperConfig); + this.#setupAutoClearOptions(cookieConsentWrapper, wrapperConfig); + this.#setupConsentModalOptions(cookieConsentWrapper, wrapperConfig); + this.#setupSettingsModalOptions(cookieConsentWrapper, wrapperConfig); + this.#setupUiOptions(cookieConsentWrapper, wrapperConfig); + this.#setupStoragePool(cookieConsentWrapper, wrapperConfig); + this.#setupEventTriggers(cookieConsentWrapper, wrapperConfig); + this.#setupLocales(cookieConsentWrapper, wrapperConfig); + this.#setupTranslations(cookieConsentWrapper, wrapperConfig); + this.#setupCmpApiOptions(cookieConsentWrapper, wrapperConfig); + + if ('cookieConsentWrapperEvents' in window) { + for (let i = 0; i < window.cookieConsentWrapperEvents.length; i++) { + const eventArgs = window.cookieConsentWrapperEvents[i]; + + if (eventArgs[0] && eventArgs[1]) { + cookieConsentWrapper.on(eventArgs[0], eventArgs[1], eventArgs[2] || null); + } + } + + window.cookieConsentWrapperEvents = { + push: eventArgs => { + if (eventArgs[0] && eventArgs[1]) { + cookieConsentWrapper.on(eventArgs[0], eventArgs[1], eventArgs[2] || null); + } + }, + } + } cookieConsentWrapper.init(window, document); return cookieConsentWrapper; } - _createGtagFunction() { + #createGtagFunction() { let gtag = window.gtag; if (!gtag) { @@ -42,7 +60,7 @@ class CookieConsentWrapperFactory { return gtag; } - _setupUser(wrapper, wrapperConfig) { + #setupUser(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('user_options') && 'object' === typeof wrapperConfig.user_options) { if (wrapperConfig.user_options.hasOwnProperty('identity') && wrapperConfig.user_options.identity) { wrapper.setStaticUserIdentity(wrapperConfig.user_options.identity); @@ -54,37 +72,37 @@ class CookieConsentWrapperFactory { } } - _setupPluginOptions(wrapper, wrapperConfig) { + #setupPluginOptions(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('plugin_options') && 'object' === typeof wrapperConfig.plugin_options) { wrapper.setPluginOptions(wrapperConfig.plugin_options); } } - _setupAutoClearOptions(wrapper, wrapperConfig) { + #setupAutoClearOptions(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('auto_clear_options') && 'object' === typeof wrapperConfig.auto_clear_options) { wrapper.setAutoClearOptions(wrapperConfig.auto_clear_options); } } - _setupConsentModalOptions(wrapper, wrapperConfig) { + #setupConsentModalOptions(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('consent_modal_options') && 'object' === typeof wrapperConfig.consent_modal_options) { wrapper.setConsentModalOptions(wrapperConfig.consent_modal_options); } } - _setupSettingsModalOptions(wrapper, wrapperConfig) { + #setupSettingsModalOptions(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('settings_modal_options') && 'object' === typeof wrapperConfig.settings_modal_options) { wrapper.setSettingsModalOptions(wrapperConfig.settings_modal_options); } } - _setupUiOptions(wrapper, wrapperConfig) { + #setupUiOptions(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('ui_options') && 'object' === typeof wrapperConfig.ui_options) { wrapper.setUiOptions(wrapperConfig.ui_options); } } - _setupStoragePool(wrapper, wrapperConfig) { + #setupStoragePool(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('storage_pool') && Array.isArray(wrapperConfig.storage_pool)) { const storagePool = wrapperConfig.storage_pool; @@ -98,7 +116,7 @@ class CookieConsentWrapperFactory { } } - _setupEventTriggers(wrapper, wrapperConfig) { + #setupEventTriggers(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('event_triggers') && Array.isArray(wrapperConfig.event_triggers)) { const eventTriggers = wrapperConfig.event_triggers; @@ -114,7 +132,7 @@ class CookieConsentWrapperFactory { } } - _setupLocales(wrapper, wrapperConfig) { + #setupLocales(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('locales') && Array.isArray(wrapperConfig.locales)) { const locales = wrapperConfig.locales; let localeKey; @@ -124,12 +142,12 @@ class CookieConsentWrapperFactory { continue; } - wrapper.loadTranslations(locales[localeKey]); + void wrapper.loadTranslations(locales[localeKey]); } } } - _setupTranslations(wrapper, wrapperConfig) { + #setupTranslations(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('translations') && 'object' === typeof wrapperConfig.translations) { const translations = wrapperConfig.translations; let locale; @@ -144,7 +162,7 @@ class CookieConsentWrapperFactory { } } - _setupCmpApiOptions(wrapper, wrapperConfig) { + #setupCmpApiOptions(wrapper, wrapperConfig) { if (wrapperConfig.hasOwnProperty('cmp_api_options') && 'object' === typeof wrapperConfig.cmp_api_options) { wrapper.setCmpApiOptions(wrapperConfig.cmp_api_options); } diff --git a/src/Translation/Catalogue.js b/src/Translation/Catalogue.js index 75d6cf2..dc829a8 100644 --- a/src/Translation/Catalogue.js +++ b/src/Translation/Catalogue.js @@ -1,6 +1,8 @@ 'use strict'; class Catalogue { + #promises = {}; + constructor(locale) { this._locale = locale; @@ -74,6 +76,25 @@ class Catalogue { return this._locale; } + loadFromUrl(url, override = false) { + if (url in this.#promises) { + return; + } + + return this.#promises[url] = fetch(url) + .then(res => res.json()) + .then(translations => { + this.merge(translations, override); + delete this.#promises[url]; + + return translations; + }) + .catch(err => { + console.warn(`CookieConsentWrapper: Unable to load translations from ${url}`, err); + delete this.#promises[url]; + }) + } + translate(key, placeholders = {}) { if (!this.hasOwnProperty(key)) { return key; @@ -92,17 +113,23 @@ class Catalogue { return translation; } - merge(translations) { + merge(translations, override = true) { let property; for (property in translations) { - if (translations.hasOwnProperty(property) && this.hasOwnProperty(property)) { + if (this.hasOwnProperty(property) && (override || '' === this[property])) { this[property] = translations[property]; } } } - exportTranslations(storagePool, config, placeholders = {}) { + async exportTranslations(storagePool, config, placeholders = {}) { + const promises = Object.values(this.#promises); + + if (promises.length) { + await Promise.all(promises); + } + const blocks = []; if ('' !== this.settings_modal_before_consent_title || '' !== this.settings_modal_before_consent_description) { diff --git a/src/Translation/Dictionary.js b/src/Translation/Dictionary.js index 32c1dad..23d3dab 100644 --- a/src/Translation/Dictionary.js +++ b/src/Translation/Dictionary.js @@ -8,6 +8,20 @@ class Dictionary { this._placeholders = {}; } + loadTranslations(locale, url, override = false) { + let catalogue; + + if (!this._catalogues.hasOwnProperty(locale)) { + catalogue = new Catalogue(locale); + + this._catalogues[locale] = catalogue; + } else { + catalogue = this._catalogues[locale]; + } + + return catalogue.loadFromUrl(url, override); + } + addTranslations(locale, translations = {}) { let catalogue; @@ -36,7 +50,7 @@ class Dictionary { return key; } - exportTranslations(storagePool, config) { + async exportTranslations(storagePool, config) { const dictionary = {}; let key; let catalogue; @@ -47,7 +61,7 @@ class Dictionary { } catalogue = this._catalogues[key]; - dictionary[catalogue.locale] = catalogue.exportTranslations(storagePool, config, this._placeholders); + dictionary[catalogue.locale] = await catalogue.exportTranslations(storagePool, config, this._placeholders); } return dictionary; diff --git a/webpack.config.dev.js b/webpack.config.dev.js index dbfad13..189bbf0 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -1,4 +1,5 @@ const path = require('path'); +const CopyPlugin = require('copy-webpack-plugin'); module.exports = { mode: "development", @@ -12,7 +13,7 @@ module.exports = { rules: [ { loader: 'babel-loader', - test: /\.js$/, + test: /\.js$/i, include: [ path.resolve(__dirname, 'src') ], @@ -21,7 +22,7 @@ module.exports = { '@babel/preset-env' ] }, - } + }, ], }, resolve: { @@ -29,8 +30,18 @@ module.exports = { 'node_modules', path.resolve(__dirname, 'src') ], - extensions: [".js", ".json", ".jsx", ".css"], + extensions: [".js"], }, + plugins: [ + new CopyPlugin({ + patterns: [ + { + from: './src/resources/translations/*.json', + to: path.resolve(__dirname, 'build', 'translations', '[name][ext]'), + }, + ], + }), + ], devServer: { static: { directory: path.join(__dirname, 'build'), diff --git a/webpack.config.prod.js b/webpack.config.prod.js index 3509a93..4996f62 100644 --- a/webpack.config.prod.js +++ b/webpack.config.prod.js @@ -1,5 +1,7 @@ const path = require('path'); const TerserWebpackPlugin = require('terser-webpack-plugin'); +const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin'); +const CopyPlugin = require('copy-webpack-plugin'); module.exports = { mode: "production", @@ -13,7 +15,7 @@ module.exports = { rules: [ { loader: 'babel-loader', - test: /\.js$/, + test: /\.js$/i, include: [ path.resolve(__dirname, 'src') ], @@ -22,7 +24,7 @@ module.exports = { '@babel/preset-env' ] }, - } + }, ], }, resolve: { @@ -30,11 +32,23 @@ module.exports = { 'node_modules', path.resolve(__dirname, 'src') ], - extensions: [".js", ".json", ".jsx", ".css"], + extensions: [".js"], }, + plugins: [ + new CopyPlugin({ + patterns: [ + { + from: './src/resources/translations/*.json', + to: path.resolve(__dirname, 'dist', 'translations', '[name][ext]'), + }, + ], + }), + ], optimization: { + minimize: true, minimizer: [ - new TerserWebpackPlugin() + new TerserWebpackPlugin(), + new JsonMinimizerPlugin(), ], }, }; From 0438454c2f09d8fe494b9c76be0cd68233b71d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 05:55:51 +0200 Subject: [PATCH 02/17] Added missing link for the version `0.5.3` in the CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea95925..38aa53a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -340,7 +340,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The first version of the package has been released. -[unreleased]: https://github.com/68publishers/cookie-consent/compare/v0.5.2...HEAD +[unreleased]: https://github.com/68publishers/cookie-consent/compare/v0.5.3...HEAD +[0.5.3]: https://github.com/68publishers/cookie-consent/compare/v0.5.2...v0.5.3 [0.5.2]: https://github.com/68publishers/cookie-consent/compare/v0.5.1...v0.5.2 [0.5.1]: https://github.com/68publishers/cookie-consent/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/68publishers/cookie-consent/compare/v0.4.8...v0.5.0 From caaa28ff736776d767f682a9a63b007108ad8f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 06:03:17 +0200 Subject: [PATCH 03/17] Removed comments from the production build --- webpack.config.prod.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/webpack.config.prod.js b/webpack.config.prod.js index 4996f62..ca8018c 100644 --- a/webpack.config.prod.js +++ b/webpack.config.prod.js @@ -47,7 +47,14 @@ module.exports = { optimization: { minimize: true, minimizer: [ - new TerserWebpackPlugin(), + new TerserWebpackPlugin({ + terserOptions: { + format: { + comments: false, + }, + }, + extractComments: false, + }), new JsonMinimizerPlugin(), ], }, From f8d75efb965da56dad6320b50046af9251aa0846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 06:10:01 +0200 Subject: [PATCH 04/17] GH Actions build - added GH Action `release-package.yml` - renamed directory `build` to `demo` - removed npm script `prepublish` --- .github/workflows/release-package.yml | 94 +++++++++++++++++++++++++++ README.md | 4 +- {build => demo}/.gitignore | 1 + {build => demo}/index.html | 0 dist/.gitignore | 3 - dist/.npmignore | 0 package.json | 3 +- webpack.config.dev.js | 6 +- 8 files changed, 101 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/release-package.yml rename {build => demo}/.gitignore (53%) rename {build => demo}/index.html (100%) delete mode 100644 dist/.gitignore delete mode 100644 dist/.npmignore diff --git a/.github/workflows/release-package.yml b/.github/workflows/release-package.yml new file mode 100644 index 0000000..c69714a --- /dev/null +++ b/.github/workflows/release-package.yml @@ -0,0 +1,94 @@ +name: Release package + +on: + workflow_dispatch: + inputs: + release-type: + description: 'Release type (one of): patch, minor, major, prepatch, preminor, premajor, prerelease' + required: true + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup node + uses: actions/setup-node@v3 + with: + registry-url: https://registry.npmjs.org/ + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Git configuration + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "GitHub Actions" + + - name: Bump release version + if: startsWith(github.event.inputs.release-type, 'pre') != true + run: | + echo "NEW_VERSION=$(npm --no-git-tag-version version $RELEASE_TYPE)" >> $GITHUB_ENV + echo "RELEASE_TAG=latest" >> $GITHUB_ENV + env: + RELEASE_TYPE: ${{ github.event.inputs.release-type }} + + - name: Bump pre-release version + if: startsWith(github.event.inputs.release-type, 'pre') + run: | + echo "NEW_VERSION=$(npm --no-git-tag-version --preid=beta version $RELEASE_TYPE)" >> $GITHUB_ENV + echo "RELEASE_TAG=beta" >> $GITHUB_ENV + env: + RELEASE_TYPE: ${{ github.event.inputs.release-type }} + + - name: Build dist + run: npm run build:prod + + - name: Update changelog + uses: superfaceai/release-changelog-action@v1 + if: startsWith(github.event.inputs.release-type, 'pre') != true + with: + path-to-changelog: CHANGELOG.md + version: ${{ env.NEW_VERSION }} + operation: release + + - name: 'Commit CHANGELOG.md, package.json, package-lock.json and dist changes and create tag' + run: | + git add "package.json" + git add "package-lock.json" + git add "dist/" + git add "CHANGELOG.md" + git commit -m "chore: release ${{ env.NEW_VERSION }}" + git tag ${{ env.NEW_VERSION }} + + - name: Publish + run: npm publish --verbose --access public --tag ${{ env.RELEASE_TAG }} + env: + NODE_AUTH_TOKEN: ${{ secrets.NPMJS_ACCESS_TOKEN }} + + - name: Push changes to repository + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git push origin && git push --tags + + - id: get-changelog + name: Get version changelog + uses: superfaceai/release-changelog-action@v1 + if: startsWith(github.event.inputs.release-type, 'pre') != true + with: + path-to-changelog: CHANGELOG.md + version: ${{ env.NEW_VERSION }} + operation: read + + - name: Update GitHub release documentation + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.NEW_VERSION }} + body: ${{ steps.get-changelog.outputs.changelog }} + prerelease: ${{ startsWith(github.event.inputs.release-type, 'pre') }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 2beb985..7bfc05b 100644 --- a/README.md +++ b/README.md @@ -425,10 +425,10 @@ $ npm run build:dev # or prod ``` Paths of output files are: - - `~/build/cookie-consent.js` (dev mode) + - `~/demo/cookie-consent.js` (dev mode) - `~/dist/cookie-consent.min.js` (production mode) -A simple demo page without real GTM is located in `~/build/index.html`. To show the demo in your browser run: +A simple demo page without real GTM is located in `~/demo/index.html`. To show the demo in your browser run: ```sh $ npm run start:dev diff --git a/build/.gitignore b/demo/.gitignore similarity index 53% rename from build/.gitignore rename to demo/.gitignore index ad83d75..e7fbd36 100644 --- a/build/.gitignore +++ b/demo/.gitignore @@ -1,2 +1,3 @@ * +!.gitignore !index.html diff --git a/build/index.html b/demo/index.html similarity index 100% rename from build/index.html rename to demo/index.html diff --git a/dist/.gitignore b/dist/.gitignore deleted file mode 100644 index 2f41fac..0000000 --- a/dist/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!.npmignore diff --git a/dist/.npmignore b/dist/.npmignore deleted file mode 100644 index e69de29..0000000 diff --git a/package.json b/package.json index 8c7ae2b..599e76b 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,7 @@ "scripts": { "build:dev": "webpack --config webpack.config.dev.js --progress --profile", "build:prod": "webpack --config webpack.config.prod.js --progress --profile", - "start:dev": "webpack --config webpack.config.dev.js --progress --profile && webpack-dev-server --config webpack.config.dev.js", - "prepublish": "npm run build:prod" + "start:dev": "webpack --config webpack.config.dev.js --progress --profile && webpack-dev-server --config webpack.config.dev.js" }, "keywords": [ "68publishers", diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 189bbf0..e2da842 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -5,7 +5,7 @@ module.exports = { mode: "development", entry: './index.js', output: { - path: path.resolve(__dirname, 'build'), + path: path.resolve(__dirname, 'demo'), filename: 'cookie-consent.js', library: 'CookieConsentWrapper' }, @@ -37,14 +37,14 @@ module.exports = { patterns: [ { from: './src/resources/translations/*.json', - to: path.resolve(__dirname, 'build', 'translations', '[name][ext]'), + to: path.resolve(__dirname, 'demo', 'translations', '[name][ext]'), }, ], }), ], devServer: { static: { - directory: path.join(__dirname, 'build'), + directory: path.join(__dirname, 'demo'), }, compress: true, port: 3000 From a532514aeee30b472ef2919b199a9e415df5ec1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 06:18:07 +0200 Subject: [PATCH 05/17] chore: release 1.0.0-beta.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 70899f7..cd36fb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "68publishers-cookie-consent", - "version": "0.5.3", + "version": "1.0.0-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "68publishers-cookie-consent", - "version": "0.5.3", + "version": "1.0.0-beta.0", "license": "MIT", "dependencies": { "crypto-js": "^4.1.1", diff --git a/package.json b/package.json index 599e76b..d5aa0d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "68publishers-cookie-consent", - "version": "0.5.3", + "version": "1.0.0-beta.0", "description": "Cookie consent wrapper based on orestbida/cookieconsent with GTM integration.", "homepage": "http://www.68publishers.io/", "main": "index.js", From 62645bffc5161248eade24f87d52f5e3e3362857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 06:21:58 +0200 Subject: [PATCH 06/17] Added path `dist/translations/*` to the field `files` in the `package.json` --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d5aa0d8..f15ec22 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "files": [ "src", "index.js", - "dist/cookie-consent.min.js" + "dist/cookie-consent.min.js", + "dist/translations/*" ] } From ced53878feb9bc09d63461df4095cb4bae71040f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Tue, 18 Jun 2024 06:23:15 +0200 Subject: [PATCH 07/17] chore: release 1.0.0-beta.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd36fb2..1d3abfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.0", + "version": "1.0.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.0", + "version": "1.0.0-beta.1", "license": "MIT", "dependencies": { "crypto-js": "^4.1.1", diff --git a/package.json b/package.json index f15ec22..9e5aaa9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.0", + "version": "1.0.0-beta.1", "description": "Cookie consent wrapper based on orestbida/cookieconsent with GTM integration.", "homepage": "http://www.68publishers.io/", "main": "index.js", From 3af20fe7f39a606f4bab6c0db455f463106663c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 03:47:42 +0200 Subject: [PATCH 08/17] Bundle size improvements - removed dependency on `whatwg-fetch` - refactored thw whole package to ESM - removed some useless code --- demo/index.html | 2 +- index.js | 9 --- index.mjs | 3 + package-lock.json | 37 +------------ package.json | 14 ++--- ...AbstractOptions.js => AbstractOptions.mjs} | 8 +-- ...toClearOptions.js => AutoClearOptions.mjs} | 6 +- .../{CmpApiOptions.js => CmpApiOptions.mjs} | 6 +- src/Config/{Config.js => Config.mjs} | 18 +++--- ...odalOptions.js => ConsentModalOptions.mjs} | 6 +- .../{PluginOptions.js => PluginOptions.mjs} | 6 +- ...dalOptions.js => SettingsModalOptions.mjs} | 6 +- src/Config/{UiOptions.js => UiOptions.mjs} | 9 ++- src/{ConsentManager.js => ConsentManager.mjs} | 28 ++-------- ...entWrapper.js => CookieConsentWrapper.mjs} | 55 +++++++++---------- ...ory.js => CookieConsentWrapperFactory.mjs} | 50 +++++------------ .../{CookieTable.js => CookieTable.mjs} | 8 +-- ...CookieTableBody.js => CookieTableBody.mjs} | 6 +- .../{CookieTables.js => CookieTables.mjs} | 8 +-- src/EventBus/{EventBus.js => EventBus.mjs} | 6 +- src/EventBus/{Events.js => Events.mjs} | 6 +- ...piIntegration.js => CmpApiIntegration.mjs} | 9 +-- .../{EventTrigger.js => EventTrigger.mjs} | 10 +--- src/Storage/{Storage.js => Storage.mjs} | 8 +-- .../{StorageConfig.js => StorageConfig.mjs} | 6 +- .../{StoragePool.js => StoragePool.mjs} | 12 ++-- .../{Catalogue.js => Catalogue.mjs} | 10 +--- .../{Dictionary.js => Dictionary.mjs} | 18 ++---- ...ggerFactory.js => ModalTriggerFactory.mjs} | 6 +- ...ylesheetLoader.js => StylesheetLoader.mjs} | 6 +- ...tonAppender.js => ThirdButtonAppender.mjs} | 6 +- ...stractIdentity.js => AbstractIdentity.mjs} | 6 +- .../{StaticIdentity.js => StaticIdentity.mjs} | 6 +- .../{StoredIdentity.js => StoredIdentity.mjs} | 6 +- src/User/{User.js => User.mjs} | 12 ++-- .../{UuidIdentity.js => UuidIdentity.mjs} | 9 +-- ...ck.config.dev.js => webpack.config.dev.mjs | 23 +++++--- ....config.prod.js => webpack.config.prod.mjs | 27 +++++---- 38 files changed, 150 insertions(+), 327 deletions(-) delete mode 100644 index.js create mode 100644 index.mjs rename src/Config/{AbstractOptions.js => AbstractOptions.mjs} (50%) rename src/Config/{AutoClearOptions.js => AutoClearOptions.mjs} (88%) rename src/Config/{CmpApiOptions.js => CmpApiOptions.mjs} (81%) rename src/Config/{Config.js => Config.mjs} (69%) rename src/Config/{ConsentModalOptions.js => ConsentModalOptions.mjs} (86%) rename src/Config/{PluginOptions.js => PluginOptions.mjs} (92%) rename src/Config/{SettingsModalOptions.js => SettingsModalOptions.mjs} (75%) rename src/Config/{UiOptions.js => UiOptions.mjs} (69%) rename src/{ConsentManager.js => ConsentManager.mjs} (89%) rename src/{CookieConsentWrapper.js => CookieConsentWrapper.mjs} (86%) rename src/{CookieConsentWrapperFactory.js => CookieConsentWrapperFactory.mjs} (67%) rename src/CookieTable/{CookieTable.js => CookieTable.mjs} (85%) rename src/CookieTable/{CookieTableBody.js => CookieTableBody.mjs} (68%) rename src/CookieTable/{CookieTables.js => CookieTables.mjs} (90%) rename src/EventBus/{EventBus.js => EventBus.mjs} (95%) rename src/EventBus/{Events.js => Events.mjs} (87%) rename src/Integration/{CmpApiIntegration.js => CmpApiIntegration.mjs} (96%) rename src/Storage/{EventTrigger.js => EventTrigger.mjs} (88%) rename src/Storage/{Storage.js => Storage.mjs} (85%) rename src/Storage/{StorageConfig.js => StorageConfig.mjs} (88%) rename src/Storage/{StoragePool.js => StoragePool.mjs} (63%) rename src/Translation/{Catalogue.js => Catalogue.mjs} (97%) rename src/Translation/{Dictionary.js => Dictionary.mjs} (78%) rename src/Ui/{ModalTriggerFactory.js => ModalTriggerFactory.mjs} (95%) rename src/Ui/{StylesheetLoader.js => StylesheetLoader.mjs} (95%) rename src/Ui/{ThirdButtonAppender.js => ThirdButtonAppender.mjs} (93%) rename src/User/{AbstractIdentity.js => AbstractIdentity.mjs} (55%) rename src/User/{StaticIdentity.js => StaticIdentity.mjs} (67%) rename src/User/{StoredIdentity.js => StoredIdentity.mjs} (85%) rename src/User/{User.js => User.mjs} (81%) rename src/User/{UuidIdentity.js => UuidIdentity.mjs} (59%) rename webpack.config.dev.js => webpack.config.dev.mjs (69%) rename webpack.config.prod.js => webpack.config.prod.mjs (68%) diff --git a/demo/index.html b/demo/index.html index a6926cf..bd54e3e 100644 --- a/demo/index.html +++ b/demo/index.html @@ -129,7 +129,7 @@ }]); - +
diff --git a/index.js b/index.js deleted file mode 100644 index add3261..0000000 --- a/index.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -const CookieConsentWrapperFactory = require('./src/CookieConsentWrapperFactory'); - -module.exports = (function () { - const factory = new CookieConsentWrapperFactory(); - - return factory.create(); -})(); diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..9fcc231 --- /dev/null +++ b/index.mjs @@ -0,0 +1,3 @@ +import { CookieConsentWrapperFactory } from './src/CookieConsentWrapperFactory.mjs'; + +export default (new CookieConsentWrapperFactory()).create(); diff --git a/package-lock.json b/package-lock.json index 1d3abfe..639ecea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,7 @@ "dependencies": { "crypto-js": "^4.1.1", "uuid": "^8.3.2", - "vanilla-cookieconsent": "^2.8.6", - "whatwg-fetch": "^3.6.2" + "vanilla-cookieconsent": "^2.8.6" }, "devDependencies": { "@babel/core": "^7.16.0", @@ -21,7 +20,6 @@ "babel-loader": "^8.2.3", "copy-webpack-plugin": "^12.0.2", "json-minimizer-webpack-plugin": "^5.0.0", - "path": "^0.12.7", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", "webpack-cli": "^4.9.1", @@ -4662,16 +4660,6 @@ "node": ">= 0.8" } }, - "node_modules/path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", - "dev": true, - "dependencies": { - "process": "^0.11.1", - "util": "^0.10.3" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4753,15 +4741,6 @@ "node": ">=8" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5726,15 +5705,6 @@ "punycode": "^2.1.0" } }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6198,11 +6168,6 @@ "node": ">=0.8.0" } }, - "node_modules/whatwg-fetch": { - "version": "3.6.19", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz", - "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw==" - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", diff --git a/package.json b/package.json index 9e5aaa9..c18de13 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,15 @@ "version": "1.0.0-beta.1", "description": "Cookie consent wrapper based on orestbida/cookieconsent with GTM integration.", "homepage": "http://www.68publishers.io/", - "main": "index.js", + "main": "index.mjs", "repository": { "type": "git", "url": "git+https://github.com/68publishers/cookie-consent" }, "scripts": { - "build:dev": "webpack --config webpack.config.dev.js --progress --profile", - "build:prod": "webpack --config webpack.config.prod.js --progress --profile", - "start:dev": "webpack --config webpack.config.dev.js --progress --profile && webpack-dev-server --config webpack.config.dev.js" + "build:dev": "webpack --config webpack.config.dev.mjs --progress --profile", + "build:prod": "webpack --config webpack.config.prod.mjs --progress --profile", + "start:dev": "webpack --config webpack.config.dev.mjs --progress --profile && webpack-dev-server --config webpack.config.dev.mjs" }, "keywords": [ "68publishers", @@ -28,7 +28,6 @@ "babel-loader": "^8.2.3", "copy-webpack-plugin": "^12.0.2", "json-minimizer-webpack-plugin": "^5.0.0", - "path": "^0.12.7", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", "webpack-cli": "^4.9.1", @@ -37,12 +36,11 @@ "dependencies": { "crypto-js": "^4.1.1", "uuid": "^8.3.2", - "vanilla-cookieconsent": "^2.8.6", - "whatwg-fetch": "^3.6.2" + "vanilla-cookieconsent": "^2.8.6" }, "files": [ "src", - "index.js", + "index.mjs", "dist/cookie-consent.min.js", "dist/translations/*" ] diff --git a/src/Config/AbstractOptions.js b/src/Config/AbstractOptions.mjs similarity index 50% rename from src/Config/AbstractOptions.js rename to src/Config/AbstractOptions.mjs index ed86f10..7bd33fb 100644 --- a/src/Config/AbstractOptions.js +++ b/src/Config/AbstractOptions.mjs @@ -1,15 +1,11 @@ -'use strict'; - -class AbstractOptions { +export class AbstractOptions { merge(options) { let property; for (property in options) { - if (options.hasOwnProperty(property) && this.hasOwnProperty(property)) { + if (this.hasOwnProperty(property)) { this[property] = options[property]; } } } } - -module.exports = AbstractOptions; diff --git a/src/Config/AutoClearOptions.js b/src/Config/AutoClearOptions.mjs similarity index 88% rename from src/Config/AutoClearOptions.js rename to src/Config/AutoClearOptions.mjs index db9a74c..b360d7d 100644 --- a/src/Config/AutoClearOptions.js +++ b/src/Config/AutoClearOptions.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractOptions } from './AbstractOptions.mjs'; -class AutoClearOptions extends require('./AbstractOptions') { +export class AutoClearOptions extends AbstractOptions { constructor() { super(); @@ -29,5 +29,3 @@ class AutoClearOptions extends require('./AbstractOptions') { super.merge(options); } } - -module.exports = AutoClearOptions; diff --git a/src/Config/CmpApiOptions.js b/src/Config/CmpApiOptions.mjs similarity index 81% rename from src/Config/CmpApiOptions.js rename to src/Config/CmpApiOptions.mjs index b58931b..a7708ae 100644 --- a/src/Config/CmpApiOptions.js +++ b/src/Config/CmpApiOptions.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractOptions } from './AbstractOptions.mjs'; -class CmpApiOptions extends require('./AbstractOptions') { +export class CmpApiOptions extends AbstractOptions { constructor() { super(); @@ -23,5 +23,3 @@ class CmpApiOptions extends require('./AbstractOptions') { return window.location.hostname.replace('www.',''); } } - -module.exports = CmpApiOptions; diff --git a/src/Config/Config.js b/src/Config/Config.mjs similarity index 69% rename from src/Config/Config.js rename to src/Config/Config.mjs index a33acd8..e1b2ad8 100644 --- a/src/Config/Config.js +++ b/src/Config/Config.mjs @@ -1,13 +1,11 @@ -'use strict'; +import { PluginOptions } from './PluginOptions.mjs'; +import { ConsentModalOptions } from './ConsentModalOptions.mjs'; +import { SettingsModalOptions } from './SettingsModalOptions.mjs'; +import { UiOptions } from './UiOptions.mjs'; +import { AutoClearOptions } from './AutoClearOptions.mjs'; +import { CmpApiOptions } from './CmpApiOptions.mjs'; -const PluginOptions = require('./PluginOptions'); -const ConsentModalOptions = require('./ConsentModalOptions'); -const SettingsModalOptions = require('./SettingsModalOptions'); -const UiOptions = require('./UiOptions'); -const AutoClearOptions = require('./AutoClearOptions'); -const CmpApiOptions = require('./CmpApiOptions'); - -class Config { +export class Config { constructor() { this.pluginOptions = new PluginOptions(); this.consentModalOptions = new ConsentModalOptions(); @@ -32,5 +30,3 @@ class Config { return config; } } - -module.exports = Config; diff --git a/src/Config/ConsentModalOptions.js b/src/Config/ConsentModalOptions.mjs similarity index 86% rename from src/Config/ConsentModalOptions.js rename to src/Config/ConsentModalOptions.mjs index 6fdc748..82e57de 100644 --- a/src/Config/ConsentModalOptions.js +++ b/src/Config/ConsentModalOptions.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractOptions } from './AbstractOptions.mjs'; -class ConsentModalOptions extends require('./AbstractOptions') { +export class ConsentModalOptions extends AbstractOptions { constructor() { super(); @@ -24,5 +24,3 @@ class ConsentModalOptions extends require('./AbstractOptions') { }; } } - -module.exports = ConsentModalOptions; diff --git a/src/Config/PluginOptions.js b/src/Config/PluginOptions.mjs similarity index 92% rename from src/Config/PluginOptions.js rename to src/Config/PluginOptions.mjs index a79516c..5f2d3a3 100644 --- a/src/Config/PluginOptions.js +++ b/src/Config/PluginOptions.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractOptions } from './AbstractOptions.mjs'; -class PluginOptions extends require('./AbstractOptions') { +export class PluginOptions extends AbstractOptions { constructor() { super(); @@ -41,5 +41,3 @@ class PluginOptions extends require('./AbstractOptions') { return config; } } - -module.exports = PluginOptions; diff --git a/src/Config/SettingsModalOptions.js b/src/Config/SettingsModalOptions.mjs similarity index 75% rename from src/Config/SettingsModalOptions.js rename to src/Config/SettingsModalOptions.mjs index e269798..26179b6 100644 --- a/src/Config/SettingsModalOptions.js +++ b/src/Config/SettingsModalOptions.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractOptions } from './AbstractOptions.mjs'; -class SettingsModalOptions extends require('./AbstractOptions') { +export class SettingsModalOptions extends AbstractOptions { constructor() { super(); @@ -18,5 +18,3 @@ class SettingsModalOptions extends require('./AbstractOptions') { }; } } - -module.exports = SettingsModalOptions; diff --git a/src/Config/UiOptions.js b/src/Config/UiOptions.mjs similarity index 69% rename from src/Config/UiOptions.js rename to src/Config/UiOptions.mjs index 7478816..eb4c01c 100644 --- a/src/Config/UiOptions.js +++ b/src/Config/UiOptions.mjs @@ -1,8 +1,9 @@ -'use strict'; +import { AbstractOptions } from './AbstractOptions.mjs'; +import ccPkg from 'vanilla-cookieconsent/package.json'; -const ccVersion = require('vanilla-cookieconsent/package.json').version; +const ccVersion = ccPkg.version; -class UiOptions extends require('./AbstractOptions') { +export class UiOptions extends AbstractOptions { constructor() { super(); @@ -21,5 +22,3 @@ class UiOptions extends require('./AbstractOptions') { return []; } } - -module.exports = UiOptions; diff --git a/src/ConsentManager.js b/src/ConsentManager.mjs similarity index 89% rename from src/ConsentManager.js rename to src/ConsentManager.mjs index cc45835..5d033dc 100644 --- a/src/ConsentManager.js +++ b/src/ConsentManager.mjs @@ -1,9 +1,7 @@ -'use strict'; +import { AutoClearOptions } from './Config/AutoClearOptions.mjs'; +import { Events } from './EventBus/Events.mjs'; -const AutoClearOptions = require('./Config/AutoClearOptions'); -const Events = require('./EventBus/Events'); - -class ConsentManager { +export class ConsentManager { constructor(cookieConsent, eventBus, config, storagePool, eventTriggers, gtag) { this._cookieConsent = cookieConsent; this._eventBus = eventBus; @@ -40,7 +38,7 @@ class ConsentManager { if (0 < changedCategories.length) { for (let changedCategoryKey in changedCategories) { - if (!changedCategories.hasOwnProperty(changedCategoryKey) || !consent.hasOwnProperty(changedCategories[changedCategoryKey])) { + if (!consent.hasOwnProperty(changedCategories[changedCategoryKey])) { continue; } @@ -61,10 +59,6 @@ class ConsentManager { const consent = {}; for (let storageKey in storageArr) { - if (!storageArr.hasOwnProperty(storageKey)) { - continue; - } - const storage = storageArr[storageKey]; const checkName = null !== storage.syncConsentWith ? storage.syncConsentWith : storage.name; @@ -80,10 +74,6 @@ class ConsentManager { const accepted = []; for (let storageKey in storageArr) { - if (!storageArr.hasOwnProperty(storageKey)) { - continue; - } - const storage = storageArr[storageKey]; const checkName = null !== storage.syncConsentWith ? storage.syncConsentWith : storage.name; const allowed = this._cookieConsent.allowedCategory(checkName); @@ -105,10 +95,6 @@ class ConsentManager { let eventTrigger; for (eventTriggerKey in this._eventTriggers) { - if (!this._eventTriggers.hasOwnProperty(eventTriggerKey)) { - continue; - } - eventTrigger = this._eventTriggers[eventTriggerKey]; if (eventTrigger.tryInvoke(this._gtag, accepted)) { @@ -187,10 +173,6 @@ class ConsentManager { const storageArr = this._storagePool.all(); for (let storageKey in storageArr) { - if (!storageArr.hasOwnProperty(storageKey)) { - continue; - } - const storage = storageArr[storageKey]; const checkName = null !== storage.syncConsentWith ? storage.syncConsentWith : storage.name; @@ -216,5 +198,3 @@ class ConsentManager { } } } - -module.exports = ConsentManager; diff --git a/src/CookieConsentWrapper.js b/src/CookieConsentWrapper.mjs similarity index 86% rename from src/CookieConsentWrapper.js rename to src/CookieConsentWrapper.mjs index 7371f38..23e6dec 100644 --- a/src/CookieConsentWrapper.js +++ b/src/CookieConsentWrapper.mjs @@ -1,25 +1,25 @@ -'use strict'; - -require('vanilla-cookieconsent'); - -const version = require('../package.json').version; -const Config = require('./Config/Config'); -const Storage = require('./Storage/Storage'); -const StoragePool = require('./Storage/StoragePool'); -const ConsentManager = require('./ConsentManager'); -const Dictionary = require('./Translation/Dictionary'); -const StylesheetLoader = require('./Ui/StylesheetLoader'); -const ModalTriggerFactory = require('./Ui/ModalTriggerFactory'); -const EventBus = require('./EventBus/EventBus'); -const Events = require('./EventBus/Events'); -const EventTrigger = require('./Storage/EventTrigger'); -const User = require('./User/User'); -const Sha256 = require('crypto-js/sha256'); -const CmpApiIntegration = require('./Integration/CmpApiIntegration'); -const ThirdButtonAppender = require('./Ui/ThirdButtonAppender'); -const CookieTables = require('./CookieTable/CookieTables'); - -class CookieConsentWrapper { +import 'vanilla-cookieconsent'; +import pkg from '../package.json'; +import { Config } from './Config/Config.mjs'; +import { Storage } from './Storage/Storage.mjs'; +import { StoragePool } from './Storage/StoragePool.mjs'; +import { ConsentManager } from './ConsentManager.mjs'; +import { Dictionary } from './Translation/Dictionary.mjs'; +import { StylesheetLoader } from './Ui/StylesheetLoader.mjs'; +import { ModalTriggerFactory } from './Ui/ModalTriggerFactory.mjs'; +import { EventBus } from './EventBus/EventBus.mjs'; +import { Events } from './EventBus/Events.mjs'; +import { EventTrigger } from './Storage/EventTrigger.mjs'; +import { User } from './User/User.mjs'; +import { ThirdButtonAppender } from './Ui/ThirdButtonAppender.mjs'; +import { CookieTables } from './CookieTable/CookieTables.mjs'; + +import { integrateCmpApi } from './Integration/CmpApiIntegration.mjs'; +import sha256 from 'crypto-js/sha256.js'; + +const version = pkg.version; + +export class CookieConsentWrapper { constructor(gtag) { this._initializationTriggered = false; this._initialized = false; @@ -60,8 +60,9 @@ class CookieConsentWrapper { }; const storages = this._storagePool.all(); - for (let name in storages) { - configuration.storages[name] = storages[name].config; + for (let index in storages) { + const storage = storages[index]; + configuration.storages[storage.name] = storage.config; } const configurationString = JSON.stringify(configuration); @@ -69,7 +70,7 @@ class CookieConsentWrapper { return { configuration: configuration, - checksum: Sha256(configurationString).toString(), + checksum: sha256(configurationString).toString(), }; } @@ -245,7 +246,7 @@ class CookieConsentWrapper { modalTriggerElements = modalTriggerFactory.create(self._config.settingsModalOptions.modal_trigger_selector, self._config.pluginOptions.current_lang || document.documentElement.lang); } - CmpApiIntegration(self, self._config.cmpApiOptions); + integrateCmpApi(self, self._config.cmpApiOptions); if (self._config.consentModalOptions.show_third_button) { self.on(Events.ON_INIT, function () { @@ -274,5 +275,3 @@ class CookieConsentWrapper { } } } - -module.exports = CookieConsentWrapper; diff --git a/src/CookieConsentWrapperFactory.js b/src/CookieConsentWrapperFactory.mjs similarity index 67% rename from src/CookieConsentWrapperFactory.js rename to src/CookieConsentWrapperFactory.mjs index 7c82a77..e5e5f4f 100644 --- a/src/CookieConsentWrapperFactory.js +++ b/src/CookieConsentWrapperFactory.mjs @@ -1,8 +1,6 @@ -'use strict'; +import { CookieConsentWrapper } from './CookieConsentWrapper.mjs'; -const CookieConsentWrapper = require('./CookieConsentWrapper'); - -class CookieConsentWrapperFactory { +export class CookieConsentWrapperFactory { create() { if (window === undefined) { throw new Error('the window is not accessible.'); @@ -61,70 +59,62 @@ class CookieConsentWrapperFactory { } #setupUser(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('user_options') && 'object' === typeof wrapperConfig.user_options) { - if (wrapperConfig.user_options.hasOwnProperty('identity') && wrapperConfig.user_options.identity) { + if ('user_options' in wrapperConfig && 'object' === typeof wrapperConfig.user_options) { + if ('identity' in wrapperConfig.user_options && wrapperConfig.user_options.identity) { wrapper.setStaticUserIdentity(wrapperConfig.user_options.identity); } - if (wrapperConfig.user_options.hasOwnProperty('attributes') && 'object' === typeof wrapperConfig.user_options.attributes) { + if ('attributes' in wrapperConfig.user_options && 'object' === typeof wrapperConfig.user_options.attributes) { wrapper.user.attributes = wrapperConfig.user_options.attributes; } } } #setupPluginOptions(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('plugin_options') && 'object' === typeof wrapperConfig.plugin_options) { + if ('plugin_options' in wrapperConfig && 'object' === typeof wrapperConfig.plugin_options) { wrapper.setPluginOptions(wrapperConfig.plugin_options); } } #setupAutoClearOptions(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('auto_clear_options') && 'object' === typeof wrapperConfig.auto_clear_options) { + if ('auto_clear_options' in wrapperConfig && 'object' === typeof wrapperConfig.auto_clear_options) { wrapper.setAutoClearOptions(wrapperConfig.auto_clear_options); } } #setupConsentModalOptions(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('consent_modal_options') && 'object' === typeof wrapperConfig.consent_modal_options) { + if ('consent_modal_options' in wrapperConfig && 'object' === typeof wrapperConfig.consent_modal_options) { wrapper.setConsentModalOptions(wrapperConfig.consent_modal_options); } } #setupSettingsModalOptions(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('settings_modal_options') && 'object' === typeof wrapperConfig.settings_modal_options) { + if ('settings_modal_options' in wrapperConfig && 'object' === typeof wrapperConfig.settings_modal_options) { wrapper.setSettingsModalOptions(wrapperConfig.settings_modal_options); } } #setupUiOptions(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('ui_options') && 'object' === typeof wrapperConfig.ui_options) { + if ('ui_options' in wrapperConfig && 'object' === typeof wrapperConfig.ui_options) { wrapper.setUiOptions(wrapperConfig.ui_options); } } #setupStoragePool(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('storage_pool') && Array.isArray(wrapperConfig.storage_pool)) { + if ('storage_pool' in wrapperConfig && Array.isArray(wrapperConfig.storage_pool)) { const storagePool = wrapperConfig.storage_pool; for (let i in storagePool) { - if (!storagePool.hasOwnProperty(i)) { - continue; - } - wrapper.addStorage(storagePool[i] || {}); } } } #setupEventTriggers(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('event_triggers') && Array.isArray(wrapperConfig.event_triggers)) { + if ('event_triggers' in wrapperConfig && Array.isArray(wrapperConfig.event_triggers)) { const eventTriggers = wrapperConfig.event_triggers; for (let i in eventTriggers) { - if (!eventTriggers.hasOwnProperty(i)) { - continue; - } - const eventTrigger = eventTriggers[i]; wrapper.addEventTrigger(eventTrigger.name, eventTrigger.storage_names, eventTrigger.type); @@ -133,40 +123,30 @@ class CookieConsentWrapperFactory { } #setupLocales(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('locales') && Array.isArray(wrapperConfig.locales)) { + if ('locales' in wrapperConfig && Array.isArray(wrapperConfig.locales)) { const locales = wrapperConfig.locales; let localeKey; for (localeKey in locales) { - if (!locales.hasOwnProperty(localeKey)) { - continue; - } - void wrapper.loadTranslations(locales[localeKey]); } } } #setupTranslations(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('translations') && 'object' === typeof wrapperConfig.translations) { + if ('translations' in wrapperConfig && 'object' === typeof wrapperConfig.translations) { const translations = wrapperConfig.translations; let locale; for (locale in translations) { - if (!translations.hasOwnProperty(locale)) { - continue; - } - wrapper.addTranslations(locale, translations[locale] || {}); } } } #setupCmpApiOptions(wrapper, wrapperConfig) { - if (wrapperConfig.hasOwnProperty('cmp_api_options') && 'object' === typeof wrapperConfig.cmp_api_options) { + if ('cmp_api_options' in wrapperConfig && 'object' === typeof wrapperConfig.cmp_api_options) { wrapper.setCmpApiOptions(wrapperConfig.cmp_api_options); } } } - -module.exports = CookieConsentWrapperFactory; diff --git a/src/CookieTable/CookieTable.js b/src/CookieTable/CookieTable.mjs similarity index 85% rename from src/CookieTable/CookieTable.js rename to src/CookieTable/CookieTable.mjs index 7b9ad76..21f720a 100644 --- a/src/CookieTable/CookieTable.js +++ b/src/CookieTable/CookieTable.mjs @@ -1,8 +1,6 @@ -'use strict'; +import { CookieTableBody } from './CookieTableBody.mjs' -const CookieTableBody = require('./CookieTableBody'); - -class CookieTable { +export class CookieTable { constructor() { this._header = []; this._bodies = {}; @@ -39,5 +37,3 @@ class CookieTable { return this; } } - -module.exports = CookieTable; diff --git a/src/CookieTable/CookieTableBody.js b/src/CookieTable/CookieTableBody.mjs similarity index 68% rename from src/CookieTable/CookieTableBody.js rename to src/CookieTable/CookieTableBody.mjs index f0ab0d3..43e4e4b 100644 --- a/src/CookieTable/CookieTableBody.js +++ b/src/CookieTable/CookieTableBody.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class CookieTableBody { +export class CookieTableBody { constructor() { this._rows = []; } @@ -13,5 +11,3 @@ class CookieTableBody { this._rows.push(row); } } - -module.exports = CookieTableBody; diff --git a/src/CookieTable/CookieTables.js b/src/CookieTable/CookieTables.mjs similarity index 90% rename from src/CookieTable/CookieTables.js rename to src/CookieTable/CookieTables.mjs index 4776acf..1478220 100644 --- a/src/CookieTable/CookieTables.js +++ b/src/CookieTable/CookieTables.mjs @@ -1,8 +1,6 @@ -'use strict'; +import { CookieTable } from './CookieTable.mjs'; -const CookieTable = require('./CookieTable'); - -class CookieTables { +export class CookieTables { constructor() { this._cookieTables = {}; } @@ -42,5 +40,3 @@ class CookieTables { } } } - -module.exports = CookieTables; diff --git a/src/EventBus/EventBus.js b/src/EventBus/EventBus.mjs similarity index 95% rename from src/EventBus/EventBus.js rename to src/EventBus/EventBus.mjs index 24c749d..51bdb70 100644 --- a/src/EventBus/EventBus.js +++ b/src/EventBus/EventBus.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class EventBus { +export class EventBus { constructor() { this._generator = (() => { let lastId = 0; @@ -51,5 +49,3 @@ class EventBus { } } } - -module.exports = EventBus; diff --git a/src/EventBus/Events.js b/src/EventBus/Events.mjs similarity index 87% rename from src/EventBus/Events.js rename to src/EventBus/Events.mjs index 1470944..d6507d1 100644 --- a/src/EventBus/Events.js +++ b/src/EventBus/Events.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class Events { +export class Events { static get ON_INIT() { return 'init'; }; @@ -21,5 +19,3 @@ class Events { return 'locale:change'; }; } - -module.exports = Events; diff --git a/src/Integration/CmpApiIntegration.js b/src/Integration/CmpApiIntegration.mjs similarity index 96% rename from src/Integration/CmpApiIntegration.js rename to src/Integration/CmpApiIntegration.mjs index a0cda04..70489d6 100644 --- a/src/Integration/CmpApiIntegration.js +++ b/src/Integration/CmpApiIntegration.mjs @@ -1,8 +1,4 @@ -'use strict'; - const integrateConsentApi = function (wrapper, cmpApiOptions) { - const fetch = window.fetch ? window.fetch : require('whatwg-fetch').fetch; - const run = (consent) => { const user = wrapper.user; const configurationExport = wrapper.configurationExport; @@ -103,7 +99,6 @@ const integrateCookiesApi = function (wrapper, cmpApiOptions) { return; } - const fetch = window.fetch ? window.fetch : require('whatwg-fetch').fetch; const fetchedLocales = []; const cookieToRow = (cookie, locale) => { const row = {}; @@ -171,7 +166,7 @@ const integrateCookiesApi = function (wrapper, cmpApiOptions) { wrapper.on('locale:change', (loc) => run(loc)); } -module.exports = function (wrapper, cmpApiOptions) { +export function integrateCmpApi(wrapper, cmpApiOptions) { if (!cmpApiOptions.url || !cmpApiOptions.resolveProject()) { return; } @@ -183,4 +178,4 @@ module.exports = function (wrapper, cmpApiOptions) { if (true === cmpApiOptions.cookies_api_enabled) { integrateCookiesApi(wrapper, cmpApiOptions); } -}; +} diff --git a/src/Storage/EventTrigger.js b/src/Storage/EventTrigger.mjs similarity index 88% rename from src/Storage/EventTrigger.js rename to src/Storage/EventTrigger.mjs index 0963cf3..ce26b58 100644 --- a/src/Storage/EventTrigger.js +++ b/src/Storage/EventTrigger.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class EventTrigger { +export class EventTrigger { constructor(name, storageNames, type = EventTrigger.TYPE_OR) { if (!Array.isArray(storageNames)) { if ('string' !== typeof storageNames) { @@ -36,10 +34,6 @@ class EventTrigger { let invoke = false; for (storageKey in this._storageNames) { - if (!this._storageNames.hasOwnProperty(storageKey)) { - continue; - } - invoke = -1 !== acceptedStorageNames.indexOf(this._storageNames[storageKey]); if ((invoke && EventTrigger.TYPE_OR === this._type) || (!invoke && EventTrigger.TYPE_AND === this._type)) { @@ -54,5 +48,3 @@ class EventTrigger { return invoke; } } - -module.exports = EventTrigger; diff --git a/src/Storage/Storage.js b/src/Storage/Storage.mjs similarity index 85% rename from src/Storage/Storage.js rename to src/Storage/Storage.mjs index de937e8..bf821b8 100644 --- a/src/Storage/Storage.js +++ b/src/Storage/Storage.mjs @@ -1,8 +1,6 @@ -'use strict'; +import { StorageConfig } from './StorageConfig.mjs'; -const StorageConfig = require('./StorageConfig'); - -class Storage { +export class Storage { constructor(config) { this._config = new StorageConfig(config); } @@ -35,5 +33,3 @@ class Storage { return this._config.show_modal_again_expiration; } } - -module.exports = Storage; diff --git a/src/Storage/StorageConfig.js b/src/Storage/StorageConfig.mjs similarity index 88% rename from src/Storage/StorageConfig.js rename to src/Storage/StorageConfig.mjs index 9c44f67..feac5b4 100644 --- a/src/Storage/StorageConfig.js +++ b/src/Storage/StorageConfig.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class StorageConfig { +export class StorageConfig { constructor(config) { if (!config.hasOwnProperty('name') || '' === config.name) { throw new Error('Missing required property "name".') @@ -14,5 +12,3 @@ class StorageConfig { this.show_modal_again_expiration = config.show_modal_again_expiration || null; } } - -module.exports = StorageConfig; diff --git a/src/Storage/StoragePool.js b/src/Storage/StoragePool.mjs similarity index 63% rename from src/Storage/StoragePool.js rename to src/Storage/StoragePool.mjs index df6a1a8..680d2a1 100644 --- a/src/Storage/StoragePool.js +++ b/src/Storage/StoragePool.mjs @@ -1,8 +1,6 @@ -'use strict'; - -class StoragePool { +export class StoragePool { constructor() { - this._items = []; + this._items = {}; } add(storage) { @@ -10,7 +8,7 @@ class StoragePool { } has(name) { - return this._items.hasOwnProperty(name); + return name in this._items; } get(name) { @@ -22,8 +20,6 @@ class StoragePool { } all() { - return this._items; + return Object.values(this._items); } } - -module.exports = StoragePool; diff --git a/src/Translation/Catalogue.js b/src/Translation/Catalogue.mjs similarity index 97% rename from src/Translation/Catalogue.js rename to src/Translation/Catalogue.mjs index dc829a8..9318cad 100644 --- a/src/Translation/Catalogue.js +++ b/src/Translation/Catalogue.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class Catalogue { +export class Catalogue { #promises = {}; constructor(locale) { @@ -144,10 +142,6 @@ class Catalogue { let storageKey; for (storageKey in storageArr) { - if (!storageArr.hasOwnProperty(storageKey)) { - continue; - } - storage = storageArr[storageKey]; if (!storage.displayInWidget || !this.hasOwnProperty(storage.name + '_title')) { @@ -197,5 +191,3 @@ class Catalogue { } } } - -module.exports = Catalogue; diff --git a/src/Translation/Dictionary.js b/src/Translation/Dictionary.mjs similarity index 78% rename from src/Translation/Dictionary.js rename to src/Translation/Dictionary.mjs index 23d3dab..88cb503 100644 --- a/src/Translation/Dictionary.js +++ b/src/Translation/Dictionary.mjs @@ -1,8 +1,6 @@ -'use strict'; +import { Catalogue } from './Catalogue.mjs'; -const Catalogue = require('./Catalogue'); - -class Dictionary { +export class Dictionary { constructor() { this._catalogues = {}; this._placeholders = {}; @@ -11,7 +9,7 @@ class Dictionary { loadTranslations(locale, url, override = false) { let catalogue; - if (!this._catalogues.hasOwnProperty(locale)) { + if (!(locale in this._catalogues)) { catalogue = new Catalogue(locale); this._catalogues[locale] = catalogue; @@ -25,7 +23,7 @@ class Dictionary { addTranslations(locale, translations = {}) { let catalogue; - if (!this._catalogues.hasOwnProperty(locale)) { + if (!(locale in this._catalogues)) { catalogue = new Catalogue(locale); this._catalogues[locale] = catalogue; @@ -43,7 +41,7 @@ class Dictionary { } translate(locale, key) { - if (this._catalogues.hasOwnProperty(locale)) { + if (locale in this._catalogues) { return this._catalogues[locale].translate(key, this._placeholders); } @@ -56,10 +54,6 @@ class Dictionary { let catalogue; for (key in this._catalogues) { - if (!this._catalogues.hasOwnProperty(key)) { - continue; - } - catalogue = this._catalogues[key]; dictionary[catalogue.locale] = await catalogue.exportTranslations(storagePool, config, this._placeholders); } @@ -67,5 +61,3 @@ class Dictionary { return dictionary; } } - -module.exports = Dictionary; diff --git a/src/Ui/ModalTriggerFactory.js b/src/Ui/ModalTriggerFactory.mjs similarity index 95% rename from src/Ui/ModalTriggerFactory.js rename to src/Ui/ModalTriggerFactory.mjs index 9947013..81787ae 100644 --- a/src/Ui/ModalTriggerFactory.js +++ b/src/Ui/ModalTriggerFactory.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class ModalTriggerFactory { +export class ModalTriggerFactory { constructor(document, dictionary) { this._document = document; this._dictionary = dictionary; @@ -54,5 +52,3 @@ class ModalTriggerFactory { }; } } - -module.exports = ModalTriggerFactory; diff --git a/src/Ui/StylesheetLoader.js b/src/Ui/StylesheetLoader.mjs similarity index 95% rename from src/Ui/StylesheetLoader.js rename to src/Ui/StylesheetLoader.mjs index 16d7c43..d56318c 100644 --- a/src/Ui/StylesheetLoader.js +++ b/src/Ui/StylesheetLoader.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class StylesheetLoader { +export class StylesheetLoader { constructor(document) { this._document = document; } @@ -50,5 +48,3 @@ class StylesheetLoader { this._document.getElementsByTagName('head')[0].appendChild(stylesheet); } } - -module.exports = StylesheetLoader; diff --git a/src/Ui/ThirdButtonAppender.js b/src/Ui/ThirdButtonAppender.mjs similarity index 93% rename from src/Ui/ThirdButtonAppender.js rename to src/Ui/ThirdButtonAppender.mjs index 35830bc..f8808f4 100644 --- a/src/Ui/ThirdButtonAppender.js +++ b/src/Ui/ThirdButtonAppender.mjs @@ -1,6 +1,4 @@ -'use strict'; - -class ThirdButtonAppender { +export class ThirdButtonAppender { append(wrapper, document) { const consentModalOptions = wrapper._config.consentModalOptions; @@ -42,5 +40,3 @@ class ThirdButtonAppender { document.getElementById('c-bns').appendChild(button); } } - -module.exports = ThirdButtonAppender; diff --git a/src/User/AbstractIdentity.js b/src/User/AbstractIdentity.mjs similarity index 55% rename from src/User/AbstractIdentity.js rename to src/User/AbstractIdentity.mjs index 347cb5e..ae024d9 100644 --- a/src/User/AbstractIdentity.js +++ b/src/User/AbstractIdentity.mjs @@ -1,9 +1,5 @@ -'use strict'; - -class AbstractIdentity { +export class AbstractIdentity { toString() { throw new Error('Method ::toString() must be reimplemented.'); } } - -module.exports = AbstractIdentity; diff --git a/src/User/StaticIdentity.js b/src/User/StaticIdentity.mjs similarity index 67% rename from src/User/StaticIdentity.js rename to src/User/StaticIdentity.mjs index d8860de..496315e 100644 --- a/src/User/StaticIdentity.js +++ b/src/User/StaticIdentity.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractIdentity } from './AbstractIdentity.mjs'; -class StaticIdentity extends require('./AbstractIdentity') { +export class StaticIdentity extends AbstractIdentity { constructor(id) { super(); @@ -15,5 +15,3 @@ class StaticIdentity extends require('./AbstractIdentity') { return this._id; } } - -module.exports = StaticIdentity; diff --git a/src/User/StoredIdentity.js b/src/User/StoredIdentity.mjs similarity index 85% rename from src/User/StoredIdentity.js rename to src/User/StoredIdentity.mjs index 542e58a..4331f58 100644 --- a/src/User/StoredIdentity.js +++ b/src/User/StoredIdentity.mjs @@ -1,6 +1,6 @@ -'use strict'; +import { AbstractIdentity } from './AbstractIdentity.mjs'; -class StoredIdentity extends require('./AbstractIdentity') { +export class StoredIdentity extends AbstractIdentity { constructor(inner) { super(); @@ -31,5 +31,3 @@ class StoredIdentity extends require('./AbstractIdentity') { return this._id; } } - -module.exports = StoredIdentity; diff --git a/src/User/User.js b/src/User/User.mjs similarity index 81% rename from src/User/User.js rename to src/User/User.mjs index 1865670..33382be 100644 --- a/src/User/User.js +++ b/src/User/User.mjs @@ -1,10 +1,8 @@ -'use strict'; +import { UuidIdentity } from './UuidIdentity.mjs'; +import { StoredIdentity } from './StoredIdentity.mjs'; +import { StaticIdentity } from './StaticIdentity.mjs'; -const UuidIdentity = require('./UuidIdentity'); -const StoredIdentity = require('./StoredIdentity'); -const StaticIdentity = require('./StaticIdentity'); - -class User { +export class User { constructor(identity) { this._identity = identity; this._attributes = {}; @@ -51,5 +49,3 @@ class User { return this; } } - -module.exports = User; diff --git a/src/User/UuidIdentity.js b/src/User/UuidIdentity.mjs similarity index 59% rename from src/User/UuidIdentity.js rename to src/User/UuidIdentity.mjs index 57b8a10..bef7d28 100644 --- a/src/User/UuidIdentity.js +++ b/src/User/UuidIdentity.mjs @@ -1,8 +1,7 @@ -'use strict'; +import { AbstractIdentity } from './AbstractIdentity.mjs'; +import { v4 as uuidV4 } from 'uuid'; -const uuidV4 = require('uuid').v4; - -class UuidIdentity extends require('./AbstractIdentity') { +export class UuidIdentity extends AbstractIdentity { constructor() { super(); @@ -17,5 +16,3 @@ class UuidIdentity extends require('./AbstractIdentity') { return this._id; } } - -module.exports = UuidIdentity; diff --git a/webpack.config.dev.js b/webpack.config.dev.mjs similarity index 69% rename from webpack.config.dev.js rename to webpack.config.dev.mjs index e2da842..768104f 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.mjs @@ -1,19 +1,26 @@ -const path = require('path'); -const CopyPlugin = require('copy-webpack-plugin'); +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import CopyPlugin from 'copy-webpack-plugin'; -module.exports = { - mode: "development", - entry: './index.js', +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default { + mode: 'development', + entry: './index.mjs', output: { path: path.resolve(__dirname, 'demo'), filename: 'cookie-consent.js', - library: 'CookieConsentWrapper' + library: { + type: 'var', + name: 'CookieConsentWrapper', + export: 'default', + } }, module: { rules: [ { loader: 'babel-loader', - test: /\.js$/i, + test: /\.(mjs|js)$/i, include: [ path.resolve(__dirname, 'src') ], @@ -30,7 +37,7 @@ module.exports = { 'node_modules', path.resolve(__dirname, 'src') ], - extensions: [".js"], + extensions: ['.mjs', '.js'], }, plugins: [ new CopyPlugin({ diff --git a/webpack.config.prod.js b/webpack.config.prod.mjs similarity index 68% rename from webpack.config.prod.js rename to webpack.config.prod.mjs index ca8018c..1970beb 100644 --- a/webpack.config.prod.js +++ b/webpack.config.prod.mjs @@ -1,21 +1,28 @@ -const path = require('path'); -const TerserWebpackPlugin = require('terser-webpack-plugin'); -const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin'); -const CopyPlugin = require('copy-webpack-plugin'); +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import TerserWebpackPlugin from 'terser-webpack-plugin'; +import JsonMinimizerPlugin from 'json-minimizer-webpack-plugin'; +import CopyPlugin from 'copy-webpack-plugin'; -module.exports = { - mode: "production", +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default { + mode: 'production', + entry: './index.mjs', output: { path: path.resolve(__dirname, 'dist'), filename: 'cookie-consent.min.js', - library: 'CookieConsentWrapper' + library: { + type: 'var', + name: 'CookieConsentWrapper', + export: 'default', + }, }, - entry: './index.js', module: { rules: [ { loader: 'babel-loader', - test: /\.js$/i, + test: /\.(mjs|js)$/i, include: [ path.resolve(__dirname, 'src') ], @@ -32,7 +39,7 @@ module.exports = { 'node_modules', path.resolve(__dirname, 'src') ], - extensions: [".js"], + extensions: ['.mjs', '.js'], }, plugins: [ new CopyPlugin({ From 9971ba71fde7d61bef00f572576685d056b5c246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 04:32:07 +0200 Subject: [PATCH 09/17] Eslint + fixes - added eslint configuration - fixed all eslint issues - added npm scripts `eslint` and `eslint:fix` - replaced usages of function `obj.hasOwnProperty(prop)` with `prop in obj` --- eslint.config.mjs | 41 ++ package-lock.json | 919 ++++++++++++++++++++++---- package.json | 8 +- src/Config/AbstractOptions.mjs | 2 +- src/Config/AutoClearOptions.mjs | 2 +- src/Config/CmpApiOptions.mjs | 2 +- src/Config/Config.mjs | 2 +- src/Config/ConsentModalOptions.mjs | 2 +- src/Config/SettingsModalOptions.mjs | 2 +- src/Config/UiOptions.mjs | 2 +- src/ConsentManager.mjs | 4 +- src/CookieConsentWrapper.mjs | 6 +- src/CookieConsentWrapperFactory.mjs | 2 +- src/CookieTable/CookieTable.mjs | 4 +- src/CookieTable/CookieTables.mjs | 6 +- src/EventBus/EventBus.mjs | 8 +- src/Integration/CmpApiIntegration.mjs | 10 +- src/Storage/StorageConfig.mjs | 2 +- src/Translation/Catalogue.mjs | 6 +- src/Ui/StylesheetLoader.mjs | 8 - src/Ui/ThirdButtonAppender.mjs | 2 +- src/User/User.mjs | 2 - 22 files changed, 869 insertions(+), 173 deletions(-) create mode 100644 eslint.config.mjs diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..7e27146 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,41 @@ +import globals from "globals"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +export default [...compat.extends("eslint:recommended"), { + languageOptions: { + globals: { + ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, "off"])), + ...globals.browser, + }, + + ecmaVersion: "latest", + sourceType: "module", + }, + + rules: { + indent: ["error", 4, { + SwitchCase: 1, + }], + + "comma-dangle": ["error", "always-multiline"], + + "comma-spacing": ["error", { + before: false, + after: true, + }], + + "no-trailing-spaces": "error", + "eol-last": ["error", "always"], + }, +}]; diff --git a/package-lock.json b/package-lock.json index 639ecea..2e45391 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,12 @@ "@babel/core": "^7.16.0", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.16.4", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.5.0", "babel-loader": "^8.2.3", "copy-webpack-plugin": "^12.0.2", + "eslint": "^9.5.0", + "globals": "^15.6.0", "json-minimizer-webpack-plugin": "^5.0.0", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", @@ -870,6 +874,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", @@ -1684,6 +1697,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", @@ -1707,6 +1729,135 @@ "node": ">=10.0.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.16.0.tgz", + "integrity": "sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "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", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.5.0.tgz", + "integrity": "sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -2213,9 +2364,9 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2233,6 +2384,15 @@ "acorn": "^8" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2309,6 +2469,15 @@ "ansi-html": "bin/ansi-html" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -2334,6 +2503,12 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -2576,6 +2751,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001539", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz", @@ -2917,6 +3101,20 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -2939,6 +3137,12 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -3126,6 +3330,57 @@ "node": ">=0.8.0" } }, + "node_modules/eslint": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.5.0.tgz", + "integrity": "sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/config-array": "^0.16.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.5.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "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.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "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", + "levn": "^0.4.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": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -3139,6 +3394,236 @@ "node": ">=8.0.0" } }, + "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==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3194,85 +3679,35 @@ "dev": true }, "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.8.x" } }, - "node_modules/execa/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, "node_modules/express": { @@ -3366,6 +3801,12 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -3396,6 +3837,18 @@ "node": ">=0.8.0" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3471,6 +3924,25 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -3623,12 +4095,15 @@ "dev": true }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.6.0.tgz", + "integrity": "sha512-UzcJi88Hw//CurUIRa9Jxb0vgOCcuD/MNjwmXp633cyaRKkCWACkoqHCtfZv43b1kqXGg/fpOa8bwgacCeXsVg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby": { @@ -3904,6 +4379,31 @@ "node": ">= 4" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -3923,6 +4423,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4026,6 +4535,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -4139,6 +4657,18 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4151,6 +4681,12 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-minimizer-webpack-plugin": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/json-minimizer-webpack-plugin/-/json-minimizer-webpack-plugin-5.0.0.tgz", @@ -4235,6 +4771,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -4247,6 +4789,15 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -4266,6 +4817,19 @@ "shell-quote": "^1.7.3" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -4307,6 +4871,12 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4474,6 +5044,12 @@ "multicast-dns": "cli.js" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -4602,6 +5178,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -4651,6 +5244,18 @@ "node": ">=6" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -4741,6 +5346,15 @@ "node": ">=8" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5321,6 +5935,27 @@ "node": ">=8" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/shell-quote": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", @@ -5425,6 +6060,18 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -5434,6 +6081,18 @@ "node": ">=6" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -5556,6 +6215,12 @@ "source-map": "^0.6.0" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -5592,6 +6257,18 @@ "node": ">=0.6" } }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -5867,56 +6544,6 @@ "node": ">= 10" } }, - "node_modules/webpack-cli/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/webpack-cli/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack-cli/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack-cli/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/webpack-dev-middleware": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", @@ -6168,12 +6795,36 @@ "node": ">=0.8.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6206,6 +6857,18 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index c18de13..ff77258 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "scripts": { "build:dev": "webpack --config webpack.config.dev.mjs --progress --profile", "build:prod": "webpack --config webpack.config.prod.mjs --progress --profile", - "start:dev": "webpack --config webpack.config.dev.mjs --progress --profile && webpack-dev-server --config webpack.config.dev.mjs" + "start:dev": "webpack --config webpack.config.dev.mjs --progress --profile && webpack-dev-server --config webpack.config.dev.mjs", + "eslint:fix": "eslint ./index.mjs ./src --fix", + "eslint": "eslint ./index.mjs ./src" }, "keywords": [ "68publishers", @@ -25,8 +27,12 @@ "@babel/core": "^7.16.0", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.16.4", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.5.0", "babel-loader": "^8.2.3", "copy-webpack-plugin": "^12.0.2", + "eslint": "^9.5.0", + "globals": "^15.6.0", "json-minimizer-webpack-plugin": "^5.0.0", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", diff --git a/src/Config/AbstractOptions.mjs b/src/Config/AbstractOptions.mjs index 7bd33fb..f30ac9e 100644 --- a/src/Config/AbstractOptions.mjs +++ b/src/Config/AbstractOptions.mjs @@ -3,7 +3,7 @@ export class AbstractOptions { let property; for (property in options) { - if (this.hasOwnProperty(property)) { + if (property in this) { this[property] = options[property]; } } diff --git a/src/Config/AutoClearOptions.mjs b/src/Config/AutoClearOptions.mjs index b360d7d..09ba02e 100644 --- a/src/Config/AutoClearOptions.mjs +++ b/src/Config/AutoClearOptions.mjs @@ -22,7 +22,7 @@ export class AutoClearOptions extends AbstractOptions { } merge(options) { - if (options.hasOwnProperty('strategy') && -1 === [AutoClearOptions.STRATEGY_CLEAR_ALL_EXCEPT_DEFINED, AutoClearOptions.STRATEGY_CLEAR_DEFINED_ONLY, AutoClearOptions.STRATEGY_COOKIE_TABLES].indexOf(options.strategy)) { + if ('strategy' in options && -1 === [AutoClearOptions.STRATEGY_CLEAR_ALL_EXCEPT_DEFINED, AutoClearOptions.STRATEGY_CLEAR_DEFINED_ONLY, AutoClearOptions.STRATEGY_COOKIE_TABLES].indexOf(options.strategy)) { throw new Error(`AutoClear strategy ${'string' === typeof options.strategy ? options.strategy : options.strategy.toString()} is not supported.`); } diff --git a/src/Config/CmpApiOptions.mjs b/src/Config/CmpApiOptions.mjs index a7708ae..cb1d17c 100644 --- a/src/Config/CmpApiOptions.mjs +++ b/src/Config/CmpApiOptions.mjs @@ -20,6 +20,6 @@ export class CmpApiOptions extends AbstractOptions { return this.project; } - return window.location.hostname.replace('www.',''); + return window.location.hostname.replace('www.', ''); } } diff --git a/src/Config/Config.mjs b/src/Config/Config.mjs index e1b2ad8..abf7594 100644 --- a/src/Config/Config.mjs +++ b/src/Config/Config.mjs @@ -20,7 +20,7 @@ export class Config { config['gui_options'] = { consent_modal: this.consentModalOptions.exportCookieConsentConfig(), - settings_modal: this.settingsModalOptions.exportCookieConsentConfig() + settings_modal: this.settingsModalOptions.exportCookieConsentConfig(), }; if (this.autoClearOptions.enabled && AutoClearOptions.STRATEGY_COOKIE_TABLES === this.autoClearOptions.strategy) { diff --git a/src/Config/ConsentModalOptions.mjs b/src/Config/ConsentModalOptions.mjs index 82e57de..3d10c96 100644 --- a/src/Config/ConsentModalOptions.mjs +++ b/src/Config/ConsentModalOptions.mjs @@ -20,7 +20,7 @@ export class ConsentModalOptions extends AbstractOptions { layout: this.layout, position: this.position, transition: this.transition, - swap_buttons: this.swap_buttons + swap_buttons: this.swap_buttons, }; } } diff --git a/src/Config/SettingsModalOptions.mjs b/src/Config/SettingsModalOptions.mjs index 26179b6..7ae928f 100644 --- a/src/Config/SettingsModalOptions.mjs +++ b/src/Config/SettingsModalOptions.mjs @@ -14,7 +14,7 @@ export class SettingsModalOptions extends AbstractOptions { return { layout: this.layout, position: this.position, - transition: this.transition + transition: this.transition, }; } } diff --git a/src/Config/UiOptions.mjs b/src/Config/UiOptions.mjs index eb4c01c..819ddef 100644 --- a/src/Config/UiOptions.mjs +++ b/src/Config/UiOptions.mjs @@ -15,7 +15,7 @@ export class UiOptions extends AbstractOptions { get defaultStylesheets() { if (true === this.include_default_stylesheets) { return [ - `https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@${ccVersion}/dist/cookieconsent.css` + `https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@${ccVersion}/dist/cookieconsent.css`, ]; } diff --git a/src/ConsentManager.mjs b/src/ConsentManager.mjs index 5d033dc..6fbada6 100644 --- a/src/ConsentManager.mjs +++ b/src/ConsentManager.mjs @@ -38,7 +38,7 @@ export class ConsentManager { if (0 < changedCategories.length) { for (let changedCategoryKey in changedCategories) { - if (!consent.hasOwnProperty(changedCategories[changedCategoryKey])) { + if (!(changedCategories[changedCategoryKey] in consent)) { continue; } @@ -155,7 +155,7 @@ export class ConsentManager { value: { last_action_date: (new Date()).toJSON(), }, - mode: 'update' + mode: 'update', }); } diff --git a/src/CookieConsentWrapper.mjs b/src/CookieConsentWrapper.mjs index 23e6dec..e4089e9 100644 --- a/src/CookieConsentWrapper.mjs +++ b/src/CookieConsentWrapper.mjs @@ -100,10 +100,10 @@ export class CookieConsentWrapper { try{ cookieValue = JSON.parse(cookieValue) - } catch (e) { + } catch (e) { // eslint-disable-line no-unused-vars try { cookieValue = JSON.parse(decodeURIComponent(cookieValue)) - } catch (e) { + } catch (e) { // eslint-disable-line no-unused-vars cookieValue = null; } } @@ -221,7 +221,7 @@ export class CookieConsentWrapper { StylesheetLoader.loadFromConfig(document, self._config.uiOptions); // init cookie consent - self._cookieConsent = initCookieConsent(); + self._cookieConsent = window.initCookieConsent(); const consentManager = new ConsentManager(self._cookieConsent, self._eventBus, self._config, self._storagePool, Object.values(self._eventTriggers), self._gtag); diff --git a/src/CookieConsentWrapperFactory.mjs b/src/CookieConsentWrapperFactory.mjs index e5e5f4f..5d00237 100644 --- a/src/CookieConsentWrapperFactory.mjs +++ b/src/CookieConsentWrapperFactory.mjs @@ -51,7 +51,7 @@ export class CookieConsentWrapperFactory { window.dataLayer = window.dataLayer || []; gtag = function gtag() { - dataLayer.push(arguments); + window.dataLayer.push(arguments); } } diff --git a/src/CookieTable/CookieTable.mjs b/src/CookieTable/CookieTable.mjs index 21f720a..49d1912 100644 --- a/src/CookieTable/CookieTable.mjs +++ b/src/CookieTable/CookieTable.mjs @@ -20,7 +20,7 @@ export class CookieTable { } getRows(storageName) { - if (!this._bodies.hasOwnProperty(storageName)) { + if (!(storageName in this._bodies)) { return []; } @@ -28,7 +28,7 @@ export class CookieTable { } addRow(storageName, row) { - if (!this._bodies.hasOwnProperty(storageName)) { + if (!(storageName in this._bodies)) { this._bodies[storageName] = new CookieTableBody(); } diff --git a/src/CookieTable/CookieTables.mjs b/src/CookieTable/CookieTables.mjs index 1478220..e9e2891 100644 --- a/src/CookieTable/CookieTables.mjs +++ b/src/CookieTable/CookieTables.mjs @@ -6,7 +6,7 @@ export class CookieTables { } getCookieTable(locale) { - if (!this._cookieTables.hasOwnProperty(locale)) { + if (!(locale in this._cookieTables)) { this._cookieTables[locale] = new CookieTable(); } @@ -15,7 +15,7 @@ export class CookieTables { appendCookieTables(languagesConfig) { for (let locale in languagesConfig) { - if (!this._cookieTables.hasOwnProperty(locale)) { + if (!(locale in this._cookieTables)) { continue; } @@ -31,7 +31,7 @@ export class CookieTables { for (let blockIndex in config.settings_modal.blocks) { const block = config.settings_modal.blocks[blockIndex]; - if (!block.hasOwnProperty('toggle') || !block.toggle.hasOwnProperty('value')) { + if (!('toggle' in block) || !('value' in block.toggle)) { continue; } diff --git a/src/EventBus/EventBus.mjs b/src/EventBus/EventBus.mjs index 51bdb70..919fd50 100644 --- a/src/EventBus/EventBus.mjs +++ b/src/EventBus/EventBus.mjs @@ -6,7 +6,7 @@ export class EventBus { return { getNextIdentifier: function () { return lastId++; - } + }, } })(); @@ -23,7 +23,7 @@ export class EventBus { this._listeners[event] = this._listeners[event] || {}; this._listeners[event][id] = { callback: callback, - scope: scope + scope: scope, }; return function () { @@ -39,10 +39,6 @@ export class EventBus { let listener; for (listenerId in listeners) { - if (!listeners.hasOwnProperty(listenerId)) { - continue; - } - listener = listeners[listenerId]; listener.callback.call(listener.scope, ...args); diff --git a/src/Integration/CmpApiIntegration.mjs b/src/Integration/CmpApiIntegration.mjs index 70489d6..2adabe7 100644 --- a/src/Integration/CmpApiIntegration.mjs +++ b/src/Integration/CmpApiIntegration.mjs @@ -2,7 +2,7 @@ const integrateConsentApi = function (wrapper, cmpApiOptions) { const run = (consent) => { const user = wrapper.user; const configurationExport = wrapper.configurationExport; - const url = cmpApiOptions.url.replace(new RegExp('\/$'), ''); + const url = cmpApiOptions.url.replace(new RegExp('/$'), ''); const project = cmpApiOptions.resolveProject(); const userConsent = {}; @@ -34,7 +34,7 @@ const integrateConsentApi = function (wrapper, cmpApiOptions) { return Promise.reject(json); } - if (!json.hasOwnProperty('data') || !json.data.hasOwnProperty('consentSettingsExists') || true === json.data.consentSettingsExists) { + if (!('data' in json) || !('consentSettingsExists' in json.data) || true === json.data.consentSettingsExists) { return; } @@ -86,7 +86,7 @@ const integrateCookiesApi = function (wrapper, cmpApiOptions) { for (let i = 0; i < cmpApiOptions.cookie_table_headers.length; i++) { const header = cmpApiOptions.cookie_table_headers[i]; - if (!columnMappers.hasOwnProperty(header)) { + if (!(header in columnMappers)) { console.warn(`Cookie header "${header}" is not allowed.`); continue; @@ -120,7 +120,7 @@ const integrateCookiesApi = function (wrapper, cmpApiOptions) { } fetchedLocales.push(locale); - const url = cmpApiOptions.url.replace(new RegExp('\/$'), ''); + const url = cmpApiOptions.url.replace(new RegExp('/$'), ''); const project = cmpApiOptions.resolveProject(); const queryComponents = [ `locale=${locale}`, @@ -140,7 +140,7 @@ const integrateCookiesApi = function (wrapper, cmpApiOptions) { return Promise.reject(json); } - if (!json.hasOwnProperty('data') || !json.data.hasOwnProperty('cookies') || 0 >= json.data.cookies.length) { + if (!('data' in json) || !('cookies' in json.data) || 0 >= json.data.cookies.length) { return; } diff --git a/src/Storage/StorageConfig.mjs b/src/Storage/StorageConfig.mjs index feac5b4..a80955f 100644 --- a/src/Storage/StorageConfig.mjs +++ b/src/Storage/StorageConfig.mjs @@ -1,6 +1,6 @@ export class StorageConfig { constructor(config) { - if (!config.hasOwnProperty('name') || '' === config.name) { + if (!('name' in config) || '' === config.name) { throw new Error('Missing required property "name".') } diff --git a/src/Translation/Catalogue.mjs b/src/Translation/Catalogue.mjs index 9318cad..84ae7e4 100644 --- a/src/Translation/Catalogue.mjs +++ b/src/Translation/Catalogue.mjs @@ -94,7 +94,7 @@ export class Catalogue { } translate(key, placeholders = {}) { - if (!this.hasOwnProperty(key)) { + if (!(key in this)) { return key; } @@ -115,7 +115,7 @@ export class Catalogue { let property; for (property in translations) { - if (this.hasOwnProperty(property) && (override || '' === this[property])) { + if (property in this && (override || '' === this[property])) { this[property] = translations[property]; } } @@ -144,7 +144,7 @@ export class Catalogue { for (storageKey in storageArr) { storage = storageArr[storageKey]; - if (!storage.displayInWidget || !this.hasOwnProperty(storage.name + '_title')) { + if (!storage.displayInWidget || !((storage.name + '_title') in this)) { continue; } diff --git a/src/Ui/StylesheetLoader.mjs b/src/Ui/StylesheetLoader.mjs index d56318c..2f36491 100644 --- a/src/Ui/StylesheetLoader.mjs +++ b/src/Ui/StylesheetLoader.mjs @@ -13,18 +13,10 @@ export class StylesheetLoader { externalStylesheets = [...externalStylesheets, ...uiOptions.external_stylesheets]; for (stylesheetKey in externalStylesheets) { - if (!externalStylesheets.hasOwnProperty(stylesheetKey)) { - continue; - } - loader.loadExternal(externalStylesheets[stylesheetKey]); } for (stylesheetKey in internalStylesheets) { - if (!internalStylesheets.hasOwnProperty(stylesheetKey)) { - continue; - } - loader.loadInternal(internalStylesheets[stylesheetKey]); } } diff --git a/src/Ui/ThirdButtonAppender.mjs b/src/Ui/ThirdButtonAppender.mjs index f8808f4..b42d88b 100644 --- a/src/Ui/ThirdButtonAppender.mjs +++ b/src/Ui/ThirdButtonAppender.mjs @@ -21,7 +21,7 @@ export class ThirdButtonAppender { button.innerText = wrapper.translate( wrapper.unwrap().getConfig('current_lang'), - 'settings' === role ? 'consent_modal_secondary_btn_settings' : 'consent_modal_secondary_btn_accept_necessary' + 'settings' === role ? 'consent_modal_secondary_btn_settings' : 'consent_modal_secondary_btn_accept_necessary', ); button.addEventListener('click', function (e) { diff --git a/src/User/User.mjs b/src/User/User.mjs index 33382be..27c8513 100644 --- a/src/User/User.mjs +++ b/src/User/User.mjs @@ -22,8 +22,6 @@ export class User { set attributes(attributes) { this._attributes = attributes; - - return this; } addAttribute(name, value) { From 5d3eb02c2a5d90663079277325d9d30314d8e171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 04:32:46 +0200 Subject: [PATCH 10/17] Added GH Action `coding-style.yml` --- .github/workflows/coding-style.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/coding-style.yml diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml new file mode 100644 index 0000000..c998b1d --- /dev/null +++ b/.github/workflows/coding-style.yml @@ -0,0 +1,30 @@ +name: Coding style + +on: + push: + branches: + - main + tags: + - v* + pull_request: + branches: + - main + +jobs: + eslint: + name: Eslint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Eslint + run: npm run eslint From d9dd768173d214d90bd49962c20c1a42b8749a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 04:48:08 +0200 Subject: [PATCH 11/17] chore: release 1.0.0-beta.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e45391..718dda7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.1", + "version": "1.0.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.1", + "version": "1.0.0-beta.3", "license": "MIT", "dependencies": { "crypto-js": "^4.1.1", diff --git a/package.json b/package.json index ff77258..8d13bbb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.1", + "version": "1.0.0-beta.3", "description": "Cookie consent wrapper based on orestbida/cookieconsent with GTM integration.", "homepage": "http://www.68publishers.io/", "main": "index.mjs", From 1bc7c457e38002ea3e9696faeaf8a06cfd5762e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 05:14:20 +0200 Subject: [PATCH 12/17] Fixed initialization of the window variable `window.cookieConsentWrapperEvents` --- src/CookieConsentWrapperFactory.mjs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/CookieConsentWrapperFactory.mjs b/src/CookieConsentWrapperFactory.mjs index 5d00237..606521f 100644 --- a/src/CookieConsentWrapperFactory.mjs +++ b/src/CookieConsentWrapperFactory.mjs @@ -29,14 +29,14 @@ export class CookieConsentWrapperFactory { cookieConsentWrapper.on(eventArgs[0], eventArgs[1], eventArgs[2] || null); } } + } - window.cookieConsentWrapperEvents = { - push: eventArgs => { - if (eventArgs[0] && eventArgs[1]) { - cookieConsentWrapper.on(eventArgs[0], eventArgs[1], eventArgs[2] || null); - } - }, - } + window.cookieConsentWrapperEvents = { + push: eventArgs => { + if (eventArgs[0] && eventArgs[1]) { + cookieConsentWrapper.on(eventArgs[0], eventArgs[1], eventArgs[2] || null); + } + }, } cookieConsentWrapper.init(window, document); From 4358dc3dab111d8f51da430bb4a21a6be1e88688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 06:34:36 +0200 Subject: [PATCH 13/17] Added possibility to load translations via JS scripts instead of fetching JSON --- src/CookieConsentWrapper.mjs | 4 ++-- src/CookieConsentWrapperFactory.mjs | 2 +- src/Translation/Catalogue.mjs | 37 ++++++++++++++++++++++++++--- webpack.config.dev.mjs | 17 +++++++++++++ webpack.config.prod.mjs | 17 +++++++++++++ 5 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/CookieConsentWrapper.mjs b/src/CookieConsentWrapper.mjs index e4089e9..5b1ea9b 100644 --- a/src/CookieConsentWrapper.mjs +++ b/src/CookieConsentWrapper.mjs @@ -156,8 +156,8 @@ export class CookieConsentWrapper { } loadTranslations(localeOrUrl, override = false) { - let url = null; - let locale = null; + let url; + let locale; if (localeOrUrl.startsWith('https://') || localeOrUrl.startsWith('http://')) { locale = localeOrUrl.split('/').pop().split('.').shift(); diff --git a/src/CookieConsentWrapperFactory.mjs b/src/CookieConsentWrapperFactory.mjs index 606521f..d187417 100644 --- a/src/CookieConsentWrapperFactory.mjs +++ b/src/CookieConsentWrapperFactory.mjs @@ -9,6 +9,7 @@ export class CookieConsentWrapperFactory { const cookieConsentWrapper = new CookieConsentWrapper(this.#createGtagFunction()); const wrapperConfig = window.cc_wrapper_config || {}; + this.#setupLocales(cookieConsentWrapper, wrapperConfig); this.#setupUser(cookieConsentWrapper, wrapperConfig); this.#setupPluginOptions(cookieConsentWrapper, wrapperConfig); this.#setupAutoClearOptions(cookieConsentWrapper, wrapperConfig); @@ -17,7 +18,6 @@ export class CookieConsentWrapperFactory { this.#setupUiOptions(cookieConsentWrapper, wrapperConfig); this.#setupStoragePool(cookieConsentWrapper, wrapperConfig); this.#setupEventTriggers(cookieConsentWrapper, wrapperConfig); - this.#setupLocales(cookieConsentWrapper, wrapperConfig); this.#setupTranslations(cookieConsentWrapper, wrapperConfig); this.#setupCmpApiOptions(cookieConsentWrapper, wrapperConfig); diff --git a/src/Translation/Catalogue.mjs b/src/Translation/Catalogue.mjs index 84ae7e4..86fc976 100644 --- a/src/Translation/Catalogue.mjs +++ b/src/Translation/Catalogue.mjs @@ -76,11 +76,42 @@ export class Catalogue { loadFromUrl(url, override = false) { if (url in this.#promises) { - return; + return true; } - return this.#promises[url] = fetch(url) - .then(res => res.json()) + let scriptUrl = url.endsWith('.js') ? url : (url + '.js'); + let script = document.head.querySelector(`script[src='${scriptUrl}']`); + let promise; + + if (script) { + if (window.cookieConsentWrapperTranslations && scriptUrl in window.cookieConsentWrapperTranslations) { + this.merge(window.cookieConsentWrapperTranslations[scriptUrl], override); + + return true; + } + + url = scriptUrl; + promise = new Promise((resolve, reject) => { + const loadListener = () => { + script.removeEventListener('load', loadListener); + script.removeEventListener('error', errorListener); + resolve(window.cookieConsentWrapperTranslations[scriptUrl]); + }; + const errorListener = () => { + script.removeEventListener('load', loadListener); + script.removeEventListener('error', errorListener); + reject(new Error(`Unable to load script: ${scriptUrl}`)); + }; + + script.addEventListener('load', loadListener); + script.addEventListener('error', errorListener); + }); + } else { + promise = fetch(url) + .then(res => res.json()); + } + + return this.#promises[url] = promise .then(translations => { this.merge(translations, override); delete this.#promises[url]; diff --git a/webpack.config.dev.mjs b/webpack.config.dev.mjs index 768104f..8bc2b5d 100644 --- a/webpack.config.dev.mjs +++ b/webpack.config.dev.mjs @@ -46,6 +46,23 @@ export default { from: './src/resources/translations/*.json', to: path.resolve(__dirname, 'demo', 'translations', '[name][ext]'), }, + { + from: './src/resources/translations/*.json', + to: path.resolve(__dirname, 'demo', 'translations', '[name][ext].js'), + transform: { + transformer(content) { + let json = JSON.parse(content.toString()); + json = JSON.stringify(json) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); + + let code = 'window.cookieConsentWrapperTranslations = window.cookieConsentWrapperTranslations || {};'; + code += `window.cookieConsentWrapperTranslations[document.currentScript.src] = ${json};`; + + return Promise.resolve(Buffer.from(code, 'utf-8')); + }, + }, + }, ], }), ], diff --git a/webpack.config.prod.mjs b/webpack.config.prod.mjs index 1970beb..69d648b 100644 --- a/webpack.config.prod.mjs +++ b/webpack.config.prod.mjs @@ -48,6 +48,23 @@ export default { from: './src/resources/translations/*.json', to: path.resolve(__dirname, 'dist', 'translations', '[name][ext]'), }, + { + from: './src/resources/translations/*.json', + to: path.resolve(__dirname, 'dist', 'translations', '[name][ext].js'), + transform: { + transformer(content) { + let json = JSON.parse(content.toString()); + json = JSON.stringify(json) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); + + let code = 'window.cookieConsentWrapperTranslations = window.cookieConsentWrapperTranslations || {};'; + code += `window.cookieConsentWrapperTranslations[document.currentScript.src] = ${json};`; + + return Promise.resolve(Buffer.from(code, 'utf-8')); + }, + }, + }, ], }), ], From c6f52e7e5c8cd936cc337f2ad92a4b9c646f3ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 06:35:24 +0200 Subject: [PATCH 14/17] chore: release 1.0.0-beta.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 718dda7..cef7700 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.3", + "version": "1.0.0-beta.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.3", + "version": "1.0.0-beta.4", "license": "MIT", "dependencies": { "crypto-js": "^4.1.1", diff --git a/package.json b/package.json index 8d13bbb..08e8de2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "68publishers-cookie-consent", - "version": "1.0.0-beta.3", + "version": "1.0.0-beta.4", "description": "Cookie consent wrapper based on orestbida/cookieconsent with GTM integration.", "homepage": "http://www.68publishers.io/", "main": "index.mjs", From 5b68b34c572027af4cab269f09ba476226b6cfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Wed, 19 Jun 2024 07:00:28 +0200 Subject: [PATCH 15/17] Updated GTM template --- gtm_template.tpl | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/gtm_template.tpl b/gtm_template.tpl index 170a61f..787973e 100644 --- a/gtm_template.tpl +++ b/gtm_template.tpl @@ -2318,6 +2318,8 @@ if (data.cmp_api_enabled && data.cmp_api_cookies_api_enabled) { } } +const locales = data.locales; + // setup wrapper config setInWindow('cc_wrapper_config', { plugin_options: pluginOptions, @@ -2369,7 +2371,25 @@ setInWindow('cc_wrapper_config', { // inject cookie consent wrapper const packageVersion = 'latest' === data.package_version ? '' : '@' + data.package_version; -const cookieConsentWrapperScript = 'https://unpkg.com/68publishers-cookie-consent' + packageVersion + '/dist/cookie-consent.min.js'; +const scriptBaseUrl = 'https://unpkg.com/68publishers-cookie-consent' + packageVersion + '/dist/'; +const cookieConsentWrapperScript = scriptBaseUrl + 'cookie-consent.min.js'; + +for (let localeKey in locales) { + let locale = locales[localeKey]; + + if (0 === locale.lastIndexOf('https://', 0) || 0 === locale.lastIndexOf('http://', 0)) { + continue; + } + + locale = 2 < locale.length ? locale[0] + locale[1] : locale; + const localeScript = scriptBaseUrl + 'translations/' + locale + '.json.js'; + + if (queryPermission('inject_script', localeScript)) { + injectScript(localeScript, data.gtmOnSuccess, data.gtmOnFailure); + } else { + data.gtmOnFailure(); + } +} if (queryPermission('inject_script', cookieConsentWrapperScript)) { injectScript(cookieConsentWrapperScript, function () { From d5a2f08856ed8979e65b2dea8782cae56866acc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Thu, 20 Jun 2024 00:57:34 +0200 Subject: [PATCH 16/17] Fixed loading of JS translation catalogues in GTM template --- gtm_template.tpl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gtm_template.tpl b/gtm_template.tpl index 787973e..14e0861 100644 --- a/gtm_template.tpl +++ b/gtm_template.tpl @@ -2376,14 +2376,19 @@ const cookieConsentWrapperScript = scriptBaseUrl + 'cookie-consent.min.js'; for (let localeKey in locales) { let locale = locales[localeKey]; + let localeScript; if (0 === locale.lastIndexOf('https://', 0) || 0 === locale.lastIndexOf('http://', 0)) { - continue; + if (-1 === locale.indexOf('.js', locale.length - 3)) { + continue; + } + + localeScript = locale; + } else { + locale = 2 < locale.length ? locale[0] + locale[1] : locale; + localeScript = scriptBaseUrl + 'translations/' + locale + '.json.js'; } - locale = 2 < locale.length ? locale[0] + locale[1] : locale; - const localeScript = scriptBaseUrl + 'translations/' + locale + '.json.js'; - if (queryPermission('inject_script', localeScript)) { injectScript(localeScript, data.gtmOnSuccess, data.gtmOnFailure); } else { From 2d0d1811ff5287d262c075f49fb222d09312c40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Fri, 21 Jun 2024 02:28:37 +0200 Subject: [PATCH 17/17] Updated CHANGELOG --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38aa53a..b64ef21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Upgrade instructions + +- Update the GTM template. +- Consider rewriting event listeners to events of the `CookieConsentWrapper` object via variable `window.cookieConsentWrapperEvents`. For more information follow [the documentation](https://github.com/68publishers/cookie-consent/blob/v1.0.0/README.md#accessing-the-wrapper-in-the-javascript). + +### Added + +- Added safe `CookieConsentWrapper` events attaching via window variable `window.cookieConsentWrapperEvents`. +- DX: Added Eslint. +- DX: Added GitHub Actions. + +### Changed + +- Default translations are loaded dynamically based on the settings in the GTM "Locales" field. +- Added ability to load custom default translations in `.json` and `.js` format. +- Reduced compiled cookie-consent script size. +- Updated GTM template. +- Updated README. +- DX: Rewritten from CommonJS to ESM. + ## [0.5.3] - 2024-05-10 ### Added