From b4aa1c4d4a2b13ff778dcf16f7b1e57591787394 Mon Sep 17 00:00:00 2001 From: tophf Date: Mon, 30 Sep 2024 16:18:37 +0300 Subject: [PATCH 001/148] to src [pre] --- .types.d.ts => src/.types.d.ts | 0 {_locales => src/_locales}/ar/messages.json | 0 {_locales => src/_locales}/bg/messages.json | 0 {_locales => src/_locales}/cs/messages.json | 0 {_locales => src/_locales}/da/messages.json | 0 {_locales => src/_locales}/de/messages.json | 0 {_locales => src/_locales}/el/messages.json | 0 {_locales => src/_locales}/en/messages.json | 0 .../_locales}/en_GB/messages.json | 0 {_locales => src/_locales}/es/messages.json | 0 .../_locales}/es_419/messages.json | 0 {_locales => src/_locales}/et/messages.json | 0 {_locales => src/_locales}/fa/messages.json | 0 {_locales => src/_locales}/fi/messages.json | 0 {_locales => src/_locales}/fr/messages.json | 0 {_locales => src/_locales}/he/messages.json | 0 {_locales => src/_locales}/hu/messages.json | 0 {_locales => src/_locales}/it/messages.json | 0 {_locales => src/_locales}/ja/messages.json | 0 {_locales => src/_locales}/ko/messages.json | 0 {_locales => src/_locales}/lv/messages.json | 0 {_locales => src/_locales}/nl/messages.json | 0 {_locales => src/_locales}/pl/messages.json | 0 .../_locales}/pt_BR/messages.json | 0 .../_locales}/pt_PT/messages.json | 0 {_locales => src/_locales}/ro/messages.json | 0 {_locales => src/_locales}/ru/messages.json | 0 {_locales => src/_locales}/sr/messages.json | 0 {_locales => src/_locales}/sv/messages.json | 0 {_locales => src/_locales}/te/messages.json | 0 {_locales => src/_locales}/tr/messages.json | 0 {_locales => src/_locales}/uk/messages.json | 0 {_locales => src/_locales}/vi/messages.json | 0 .../_locales}/zh_CN/messages.json | 0 .../_locales}/zh_TW/messages.json | 0 .../background}/background-worker.js | 0 {background => src/background}/background.js | 0 {background => src/background}/bg-prefs.js | 0 .../background}/browser-cmd-hotkeys.js | 0 .../background}/color-scheme.js | 0 {background => src/background}/common.js | 0 .../background}/content-scripts.js | 0 .../background}/context-menus.js | 0 .../background}/db-chrome-storage.js | 0 {background => src/background}/db.js | 0 .../background}/icon-manager.js | 0 .../background}/navigation-manager.js | 0 .../background}/style-manager.js | 0 .../background}/style-search-db.js | 0 .../background}/style-via-api.js | 0 .../background}/style-via-webrequest.js | 0 .../background}/sync-manager.js | 0 {background => src/background}/tab-manager.js | 0 {background => src/background}/tab-util.js | 0 .../background}/token-manager.js | 0 .../background}/update-manager.js | 0 .../background}/usercss-install-helper.js | 0 .../background}/usercss-manager.js | 0 {background => src/background}/uso-api.js | 0 {background => src/background}/usw-api.js | 0 {content => src/content}/apply.js | 0 .../content}/install-hook-greasyfork.js | 0 .../content}/install-hook-usercss.js | 0 .../content}/install-hook-userstyles.js | 0 .../content}/install-hook-userstylesworld.js | 0 {content => src/content}/style-injector.js | 0 {css => src/css}/global-dark.css | 0 {css => src/css}/global.css | 0 {css => src/css}/icons.ttf | Bin {css => src/css}/spinner.css | 0 edit.html => src/edit.html | 0 {edit => src/edit}/autocomplete.js | 0 {edit => src/edit}/base.js | 0 {edit => src/edit}/beautify.js | 0 {edit => src/edit}/codemirror-default.css | 0 {edit => src/edit}/codemirror-default.js | 0 {edit => src/edit}/codemirror-factory.js | 0 {edit => src/edit}/codemirror-themes.js | 0 src/edit/colorpicker-helper.js | 59 +++++ src/edit/dirty-reporter.js | 91 +++++++ {edit => src/edit}/drafts.js | 0 {edit => src/edit}/edit.css | 0 {edit => src/edit}/edit.js | 0 src/edit/editor-header.js | 81 ++++++ {edit => src/edit}/editor-worker.js | 0 src/edit/editor.js | 233 ++++++++++++++++++ {edit => src/edit}/embedded-popup.js | 0 {edit => src/edit}/global-search.css | 0 {edit => src/edit}/global-search.js | 0 src/edit/index.js | 140 +++++++++++ {edit => src/edit}/linter-dialogs.js | 0 {edit => src/edit}/linter-manager.js | 0 src/edit/live-preview.js | 84 +++++++ {edit => src/edit}/moz-section-finder.js | 0 {edit => src/edit}/moz-section-widget.js | 0 src/edit/on-msg-extension.js | 54 ++++ {edit => src/edit}/regexp-tester.css | 0 {edit => src/edit}/regexp-tester.js | 0 {edit => src/edit}/sections-editor-section.js | 0 {edit => src/edit}/sections-editor.js | 0 {edit => src/edit}/settings.css | 0 {edit => src/edit}/settings.js | 0 {edit => src/edit}/show-keymap-help.js | 0 {edit => src/edit}/source-editor.js | 0 src/edit/style-ready.js | 60 +++++ src/edit/unload.js | 41 +++ {edit => src/edit}/usw-integration.js | 0 {edit => src/edit}/util.js | 0 src/edit/windowed-mode.js | 52 ++++ {images => src/images}/eyedropper/16px.png | Bin {images => src/images}/eyedropper/32px.png | Bin {images => src/images}/eyedropper/README.md | 0 {images => src/images}/icon/128.png | Bin {images => src/images}/icon/16.png | Bin {images => src/images}/icon/16w.png | Bin {images => src/images}/icon/16x.png | Bin {images => src/images}/icon/19.png | Bin {images => src/images}/icon/19w.png | Bin {images => src/images}/icon/19x.png | Bin {images => src/images}/icon/32.png | Bin {images => src/images}/icon/32w.png | Bin {images => src/images}/icon/32x.png | Bin {images => src/images}/icon/38.png | Bin {images => src/images}/icon/38w.png | Bin {images => src/images}/icon/38x.png | Bin {images => src/images}/icon/48.png | Bin {images => src/images}/icon/light/16.png | Bin {images => src/images}/icon/light/16w.png | Bin {images => src/images}/icon/light/16x.png | Bin {images => src/images}/icon/light/19.png | Bin {images => src/images}/icon/light/19w.png | Bin {images => src/images}/icon/light/19x.png | Bin {images => src/images}/icon/light/32.png | Bin {images => src/images}/icon/light/32w.png | Bin {images => src/images}/icon/light/32x.png | Bin {images => src/images}/icon/light/38.png | Bin {images => src/images}/icon/light/38w.png | Bin {images => src/images}/icon/light/38x.png | Bin {images => src/images}/icons/check1.svg | 0 {images => src/images}/icons/check2.svg | 0 {images => src/images}/icons/checked.svg | 0 {images => src/images}/icons/close.svg | 0 {images => src/images}/icons/config.svg | 0 {images => src/images}/icons/edit.svg | 0 {images => src/images}/icons/empty.svg | 0 {images => src/images}/icons/external.svg | 0 {images => src/images}/icons/info.svg | 0 {images => src/images}/icons/install.svg | 0 {images => src/images}/icons/log.svg | 0 {images => src/images}/icons/menu.svg | 0 {images => src/images}/icons/minus.svg | 0 {images => src/images}/icons/plus.svg | 0 {images => src/images}/icons/reorder.svg | 0 {images => src/images}/icons/select-arrow.svg | 0 {images => src/images}/icons/sort-down.svg | 0 {images => src/images}/icons/undo.svg | 0 {images => src/images}/icons/update-check.svg | 0 {images => src/images}/icons/usercss.svg | 0 {images => src/images}/icons/v.svg | 0 .../injection-order}/injection-order.css | 0 .../injection-order}/injection-order.js | 0 .../install-usercss.html | 0 .../install-usercss}/install-usercss.css | 0 .../install-usercss}/install-usercss.js | 0 .../install-usercss}/preinit.js | 0 {js => src/js}/browser.js | 0 {js => src/js}/cmpver.js | 0 {js => src/js}/color/LICENSE | 0 {js => src/js}/color/README.md | 0 {js => src/js}/color/color-converter.js | 0 {js => src/js}/color/color-mimicry.js | 0 {js => src/js}/color/color-picker.css | 0 {js => src/js}/color/color-picker.js | 0 {js => src/js}/color/color-view.js | 0 {js => src/js}/csslint/LICENSE | 0 {js => src/js}/csslint/README.md | 0 {js => src/js}/csslint/csslint.js | 0 {js => src/js}/csslint/parserlib-base.js | 0 {js => src/js}/csslint/parserlib.js | 0 {js => src/js}/dlg/config-dialog.css | 0 {js => src/js}/dlg/config-dialog.js | 0 {js => src/js}/dlg/message-box.css | 0 {js => src/js}/dlg/message-box.js | 0 src/js/dom-base.js | 178 +++++++++++++ {js => src/js}/dom-on-load.js | 0 src/js/dom-util.js | 216 ++++++++++++++++ {js => src/js}/dom.js | 0 {js => src/js}/header-resizer.js | 0 {js => src/js}/localization.js | 0 {js => src/js}/meta-parser.js | 0 {js => src/js}/moz-parser.js | 0 {js => src/js}/msg.js | 0 {js => src/js}/popup-get-styles.js | 0 {js => src/js}/prefs.js | 0 {js => src/js}/router.js | 0 {js => src/js}/sections-util.js | 0 {js => src/js}/storage-util.js | 0 {js => src/js}/themer.js | 0 {js => src/js}/toolbox.js | 0 {js => src/js}/usercss-compiler.js | 0 {js => src/js}/worker-util.js | 0 manage.html => src/manage.html | 0 {manage => src/manage}/events.js | 0 {manage => src/manage}/filters.js | 0 {manage => src/manage}/import-export.js | 0 {manage => src/manage}/incremental-search.js | 0 {manage => src/manage}/manage-newui.css | 0 {manage => src/manage}/manage.css | 0 {manage => src/manage}/manage.js | 0 {manage => src/manage}/render.js | 0 {manage => src/manage}/sorter.js | 0 {manage => src/manage}/updater-ui.js | 0 manifest.json => src/manifest.json | 0 options.html => src/options.html | 0 {options => src/options}/onoffswitch.css | 0 {options => src/options}/options-sync.js | 0 {options => src/options}/options.css | 0 {options => src/options}/options.js | 0 popup.html => src/popup.html | 0 {popup => src/popup}/events.js | 0 {popup => src/popup}/hotkeys.js | 0 {popup => src/popup}/popup.css | 0 {popup => src/popup}/popup.js | 0 {popup => src/popup}/search.css | 0 {popup => src/popup}/search.html | 0 {popup => src/popup}/search.js | 0 .../vendor-overwrites}/beautify/LICENSE | 68 ++--- .../vendor-overwrites}/beautify/README.md | 0 .../beautify/beautify-css-mod.js | 0 .../codemirror-addon/match-highlighter.js | 0 {vendor => src/vendor}/codemirror/LICENSE | 0 {vendor => src/vendor}/codemirror/README.md | 0 .../codemirror/addon/comment/comment.js | 0 .../codemirror/addon/dialog/dialog.css | 0 .../vendor}/codemirror/addon/dialog/dialog.js | 0 .../codemirror/addon/edit/closebrackets.js | 0 .../codemirror/addon/edit/matchbrackets.js | 0 .../codemirror/addon/fold/brace-fold.js | 0 .../codemirror/addon/fold/comment-fold.js | 0 .../vendor}/codemirror/addon/fold/foldcode.js | 0 .../codemirror/addon/fold/foldgutter.css | 0 .../codemirror/addon/fold/foldgutter.js | 0 .../codemirror/addon/fold/indent-fold.js | 0 .../codemirror/addon/hint/anyword-hint.js | 0 .../vendor}/codemirror/addon/hint/css-hint.js | 0 .../codemirror/addon/hint/show-hint.css | 0 .../codemirror/addon/hint/show-hint.js | 0 .../vendor}/codemirror/addon/lint/css-lint.js | 0 .../codemirror/addon/lint/json-lint.js | 0 .../vendor}/codemirror/addon/lint/lint.css | 0 .../vendor}/codemirror/addon/lint/lint.js | 0 .../addon/scroll/annotatescrollbar.js | 0 .../addon/search/matchesonscrollbar.css | 0 .../addon/search/matchesonscrollbar.js | 0 .../codemirror/addon/search/searchcursor.js | 0 .../codemirror/addon/selection/active-line.js | 0 .../vendor}/codemirror/keymap/emacs.js | 0 .../vendor}/codemirror/keymap/sublime.js | 0 .../vendor}/codemirror/keymap/vim.js | 0 .../vendor}/codemirror/lib/codemirror.css | 0 .../vendor}/codemirror/lib/codemirror.js | 0 .../vendor}/codemirror/mode/css/css.js | 0 .../codemirror/mode/javascript/javascript.js | 0 .../vendor}/codemirror/mode/stylus/stylus.js | 0 {vendor => src/vendor}/db-to-cloud/LICENSE | 0 {vendor => src/vendor}/db-to-cloud/README.md | 0 .../vendor}/db-to-cloud/db-to-cloud.js | 0 {vendor => src/vendor}/draggable-list/LICENSE | 0 .../vendor}/draggable-list/README.md | 0 .../draggable-list/draggable-list.iife.js | 0 {vendor => src/vendor}/jsonlint/LICENSE | 0 {vendor => src/vendor}/jsonlint/README.md | 0 {vendor => src/vendor}/jsonlint/jsonlint.js | 0 {vendor => src/vendor}/less/LICENSE | 0 {vendor => src/vendor}/less/README.md | 0 {vendor => src/vendor}/less/less.min.js | 0 .../vendor}/lz-string-unsafe/LICENSE | 0 .../vendor}/lz-string-unsafe/README.md | 0 .../lz-string-unsafe/lz-string-unsafe.min.js | 0 .../vendor}/stylelint-bundle/LICENSE | 0 .../vendor}/stylelint-bundle/README.md | 0 .../stylelint-bundle/stylelint-bundle.min.js | 0 .../vendor}/stylus-lang-bundle/LICENSE | 0 .../vendor}/stylus-lang-bundle/README.md | 0 .../stylus-lang-bundle/stylus-renderer.min.js | 0 {vendor => src/vendor}/usercss-meta/LICENSE | 0 {vendor => src/vendor}/usercss-meta/README.md | 0 .../vendor}/usercss-meta/usercss-meta.js | 0 .../webext-launch-web-auth-flow/LICENSE | 0 .../webext-launch-web-auth-flow/README.md | 0 .../webext-launch-web-auth-flow.js | 0 291 files changed, 1323 insertions(+), 34 deletions(-) rename .types.d.ts => src/.types.d.ts (100%) rename {_locales => src/_locales}/ar/messages.json (100%) rename {_locales => src/_locales}/bg/messages.json (100%) rename {_locales => src/_locales}/cs/messages.json (100%) rename {_locales => src/_locales}/da/messages.json (100%) rename {_locales => src/_locales}/de/messages.json (100%) rename {_locales => src/_locales}/el/messages.json (100%) rename {_locales => src/_locales}/en/messages.json (100%) rename {_locales => src/_locales}/en_GB/messages.json (100%) rename {_locales => src/_locales}/es/messages.json (100%) rename {_locales => src/_locales}/es_419/messages.json (100%) rename {_locales => src/_locales}/et/messages.json (100%) rename {_locales => src/_locales}/fa/messages.json (100%) rename {_locales => src/_locales}/fi/messages.json (100%) rename {_locales => src/_locales}/fr/messages.json (100%) rename {_locales => src/_locales}/he/messages.json (100%) rename {_locales => src/_locales}/hu/messages.json (100%) rename {_locales => src/_locales}/it/messages.json (100%) rename {_locales => src/_locales}/ja/messages.json (100%) rename {_locales => src/_locales}/ko/messages.json (100%) rename {_locales => src/_locales}/lv/messages.json (100%) rename {_locales => src/_locales}/nl/messages.json (100%) rename {_locales => src/_locales}/pl/messages.json (100%) rename {_locales => src/_locales}/pt_BR/messages.json (100%) rename {_locales => src/_locales}/pt_PT/messages.json (100%) rename {_locales => src/_locales}/ro/messages.json (100%) rename {_locales => src/_locales}/ru/messages.json (100%) rename {_locales => src/_locales}/sr/messages.json (100%) rename {_locales => src/_locales}/sv/messages.json (100%) rename {_locales => src/_locales}/te/messages.json (100%) rename {_locales => src/_locales}/tr/messages.json (100%) rename {_locales => src/_locales}/uk/messages.json (100%) rename {_locales => src/_locales}/vi/messages.json (100%) rename {_locales => src/_locales}/zh_CN/messages.json (100%) rename {_locales => src/_locales}/zh_TW/messages.json (100%) rename {background => src/background}/background-worker.js (100%) rename {background => src/background}/background.js (100%) rename {background => src/background}/bg-prefs.js (100%) rename {background => src/background}/browser-cmd-hotkeys.js (100%) rename {background => src/background}/color-scheme.js (100%) rename {background => src/background}/common.js (100%) rename {background => src/background}/content-scripts.js (100%) rename {background => src/background}/context-menus.js (100%) rename {background => src/background}/db-chrome-storage.js (100%) rename {background => src/background}/db.js (100%) rename {background => src/background}/icon-manager.js (100%) rename {background => src/background}/navigation-manager.js (100%) rename {background => src/background}/style-manager.js (100%) rename {background => src/background}/style-search-db.js (100%) rename {background => src/background}/style-via-api.js (100%) rename {background => src/background}/style-via-webrequest.js (100%) rename {background => src/background}/sync-manager.js (100%) rename {background => src/background}/tab-manager.js (100%) rename {background => src/background}/tab-util.js (100%) rename {background => src/background}/token-manager.js (100%) rename {background => src/background}/update-manager.js (100%) rename {background => src/background}/usercss-install-helper.js (100%) rename {background => src/background}/usercss-manager.js (100%) rename {background => src/background}/uso-api.js (100%) rename {background => src/background}/usw-api.js (100%) rename {content => src/content}/apply.js (100%) rename {content => src/content}/install-hook-greasyfork.js (100%) rename {content => src/content}/install-hook-usercss.js (100%) rename {content => src/content}/install-hook-userstyles.js (100%) rename {content => src/content}/install-hook-userstylesworld.js (100%) rename {content => src/content}/style-injector.js (100%) rename {css => src/css}/global-dark.css (100%) rename {css => src/css}/global.css (100%) rename {css => src/css}/icons.ttf (100%) rename {css => src/css}/spinner.css (100%) rename edit.html => src/edit.html (100%) rename {edit => src/edit}/autocomplete.js (100%) rename {edit => src/edit}/base.js (100%) rename {edit => src/edit}/beautify.js (100%) rename {edit => src/edit}/codemirror-default.css (100%) rename {edit => src/edit}/codemirror-default.js (100%) rename {edit => src/edit}/codemirror-factory.js (100%) rename {edit => src/edit}/codemirror-themes.js (100%) create mode 100644 src/edit/colorpicker-helper.js create mode 100644 src/edit/dirty-reporter.js rename {edit => src/edit}/drafts.js (100%) rename {edit => src/edit}/edit.css (100%) rename {edit => src/edit}/edit.js (100%) create mode 100644 src/edit/editor-header.js rename {edit => src/edit}/editor-worker.js (100%) create mode 100644 src/edit/editor.js rename {edit => src/edit}/embedded-popup.js (100%) rename {edit => src/edit}/global-search.css (100%) rename {edit => src/edit}/global-search.js (100%) create mode 100644 src/edit/index.js rename {edit => src/edit}/linter-dialogs.js (100%) rename {edit => src/edit}/linter-manager.js (100%) create mode 100644 src/edit/live-preview.js rename {edit => src/edit}/moz-section-finder.js (100%) rename {edit => src/edit}/moz-section-widget.js (100%) create mode 100644 src/edit/on-msg-extension.js rename {edit => src/edit}/regexp-tester.css (100%) rename {edit => src/edit}/regexp-tester.js (100%) rename {edit => src/edit}/sections-editor-section.js (100%) rename {edit => src/edit}/sections-editor.js (100%) rename {edit => src/edit}/settings.css (100%) rename {edit => src/edit}/settings.js (100%) rename {edit => src/edit}/show-keymap-help.js (100%) rename {edit => src/edit}/source-editor.js (100%) create mode 100644 src/edit/style-ready.js create mode 100644 src/edit/unload.js rename {edit => src/edit}/usw-integration.js (100%) rename {edit => src/edit}/util.js (100%) create mode 100644 src/edit/windowed-mode.js rename {images => src/images}/eyedropper/16px.png (100%) rename {images => src/images}/eyedropper/32px.png (100%) rename {images => src/images}/eyedropper/README.md (100%) rename {images => src/images}/icon/128.png (100%) rename {images => src/images}/icon/16.png (100%) rename {images => src/images}/icon/16w.png (100%) rename {images => src/images}/icon/16x.png (100%) rename {images => src/images}/icon/19.png (100%) rename {images => src/images}/icon/19w.png (100%) rename {images => src/images}/icon/19x.png (100%) rename {images => src/images}/icon/32.png (100%) rename {images => src/images}/icon/32w.png (100%) rename {images => src/images}/icon/32x.png (100%) rename {images => src/images}/icon/38.png (100%) rename {images => src/images}/icon/38w.png (100%) rename {images => src/images}/icon/38x.png (100%) rename {images => src/images}/icon/48.png (100%) rename {images => src/images}/icon/light/16.png (100%) rename {images => src/images}/icon/light/16w.png (100%) rename {images => src/images}/icon/light/16x.png (100%) rename {images => src/images}/icon/light/19.png (100%) rename {images => src/images}/icon/light/19w.png (100%) rename {images => src/images}/icon/light/19x.png (100%) rename {images => src/images}/icon/light/32.png (100%) rename {images => src/images}/icon/light/32w.png (100%) rename {images => src/images}/icon/light/32x.png (100%) rename {images => src/images}/icon/light/38.png (100%) rename {images => src/images}/icon/light/38w.png (100%) rename {images => src/images}/icon/light/38x.png (100%) rename {images => src/images}/icons/check1.svg (100%) rename {images => src/images}/icons/check2.svg (100%) rename {images => src/images}/icons/checked.svg (100%) rename {images => src/images}/icons/close.svg (100%) rename {images => src/images}/icons/config.svg (100%) rename {images => src/images}/icons/edit.svg (100%) rename {images => src/images}/icons/empty.svg (100%) rename {images => src/images}/icons/external.svg (100%) rename {images => src/images}/icons/info.svg (100%) rename {images => src/images}/icons/install.svg (100%) rename {images => src/images}/icons/log.svg (100%) rename {images => src/images}/icons/menu.svg (100%) rename {images => src/images}/icons/minus.svg (100%) rename {images => src/images}/icons/plus.svg (100%) rename {images => src/images}/icons/reorder.svg (100%) rename {images => src/images}/icons/select-arrow.svg (100%) rename {images => src/images}/icons/sort-down.svg (100%) rename {images => src/images}/icons/undo.svg (100%) rename {images => src/images}/icons/update-check.svg (100%) rename {images => src/images}/icons/usercss.svg (100%) rename {images => src/images}/icons/v.svg (100%) rename {injection-order => src/injection-order}/injection-order.css (100%) rename {injection-order => src/injection-order}/injection-order.js (100%) rename install-usercss.html => src/install-usercss.html (100%) rename {install-usercss => src/install-usercss}/install-usercss.css (100%) rename {install-usercss => src/install-usercss}/install-usercss.js (100%) rename {install-usercss => src/install-usercss}/preinit.js (100%) rename {js => src/js}/browser.js (100%) rename {js => src/js}/cmpver.js (100%) rename {js => src/js}/color/LICENSE (100%) rename {js => src/js}/color/README.md (100%) rename {js => src/js}/color/color-converter.js (100%) rename {js => src/js}/color/color-mimicry.js (100%) rename {js => src/js}/color/color-picker.css (100%) rename {js => src/js}/color/color-picker.js (100%) rename {js => src/js}/color/color-view.js (100%) rename {js => src/js}/csslint/LICENSE (100%) rename {js => src/js}/csslint/README.md (100%) rename {js => src/js}/csslint/csslint.js (100%) rename {js => src/js}/csslint/parserlib-base.js (100%) rename {js => src/js}/csslint/parserlib.js (100%) rename {js => src/js}/dlg/config-dialog.css (100%) rename {js => src/js}/dlg/config-dialog.js (100%) rename {js => src/js}/dlg/message-box.css (100%) rename {js => src/js}/dlg/message-box.js (100%) create mode 100644 src/js/dom-base.js rename {js => src/js}/dom-on-load.js (100%) create mode 100644 src/js/dom-util.js rename {js => src/js}/dom.js (100%) rename {js => src/js}/header-resizer.js (100%) rename {js => src/js}/localization.js (100%) rename {js => src/js}/meta-parser.js (100%) rename {js => src/js}/moz-parser.js (100%) rename {js => src/js}/msg.js (100%) rename {js => src/js}/popup-get-styles.js (100%) rename {js => src/js}/prefs.js (100%) rename {js => src/js}/router.js (100%) rename {js => src/js}/sections-util.js (100%) rename {js => src/js}/storage-util.js (100%) rename {js => src/js}/themer.js (100%) rename {js => src/js}/toolbox.js (100%) rename {js => src/js}/usercss-compiler.js (100%) rename {js => src/js}/worker-util.js (100%) rename manage.html => src/manage.html (100%) rename {manage => src/manage}/events.js (100%) rename {manage => src/manage}/filters.js (100%) rename {manage => src/manage}/import-export.js (100%) rename {manage => src/manage}/incremental-search.js (100%) rename {manage => src/manage}/manage-newui.css (100%) rename {manage => src/manage}/manage.css (100%) rename {manage => src/manage}/manage.js (100%) rename {manage => src/manage}/render.js (100%) rename {manage => src/manage}/sorter.js (100%) rename {manage => src/manage}/updater-ui.js (100%) rename manifest.json => src/manifest.json (100%) rename options.html => src/options.html (100%) rename {options => src/options}/onoffswitch.css (100%) rename {options => src/options}/options-sync.js (100%) rename {options => src/options}/options.css (100%) rename {options => src/options}/options.js (100%) rename popup.html => src/popup.html (100%) rename {popup => src/popup}/events.js (100%) rename {popup => src/popup}/hotkeys.js (100%) rename {popup => src/popup}/popup.css (100%) rename {popup => src/popup}/popup.js (100%) rename {popup => src/popup}/search.css (100%) rename {popup => src/popup}/search.html (100%) rename {popup => src/popup}/search.js (100%) rename {vendor-overwrites => src/vendor-overwrites}/beautify/LICENSE (97%) rename {vendor-overwrites => src/vendor-overwrites}/beautify/README.md (100%) rename {vendor-overwrites => src/vendor-overwrites}/beautify/beautify-css-mod.js (100%) rename {vendor-overwrites => src/vendor-overwrites}/codemirror-addon/match-highlighter.js (100%) rename {vendor => src/vendor}/codemirror/LICENSE (100%) rename {vendor => src/vendor}/codemirror/README.md (100%) rename {vendor => src/vendor}/codemirror/addon/comment/comment.js (100%) rename {vendor => src/vendor}/codemirror/addon/dialog/dialog.css (100%) rename {vendor => src/vendor}/codemirror/addon/dialog/dialog.js (100%) rename {vendor => src/vendor}/codemirror/addon/edit/closebrackets.js (100%) rename {vendor => src/vendor}/codemirror/addon/edit/matchbrackets.js (100%) rename {vendor => src/vendor}/codemirror/addon/fold/brace-fold.js (100%) rename {vendor => src/vendor}/codemirror/addon/fold/comment-fold.js (100%) rename {vendor => src/vendor}/codemirror/addon/fold/foldcode.js (100%) rename {vendor => src/vendor}/codemirror/addon/fold/foldgutter.css (100%) rename {vendor => src/vendor}/codemirror/addon/fold/foldgutter.js (100%) rename {vendor => src/vendor}/codemirror/addon/fold/indent-fold.js (100%) rename {vendor => src/vendor}/codemirror/addon/hint/anyword-hint.js (100%) rename {vendor => src/vendor}/codemirror/addon/hint/css-hint.js (100%) rename {vendor => src/vendor}/codemirror/addon/hint/show-hint.css (100%) rename {vendor => src/vendor}/codemirror/addon/hint/show-hint.js (100%) rename {vendor => src/vendor}/codemirror/addon/lint/css-lint.js (100%) rename {vendor => src/vendor}/codemirror/addon/lint/json-lint.js (100%) rename {vendor => src/vendor}/codemirror/addon/lint/lint.css (100%) rename {vendor => src/vendor}/codemirror/addon/lint/lint.js (100%) rename {vendor => src/vendor}/codemirror/addon/scroll/annotatescrollbar.js (100%) rename {vendor => src/vendor}/codemirror/addon/search/matchesonscrollbar.css (100%) rename {vendor => src/vendor}/codemirror/addon/search/matchesonscrollbar.js (100%) rename {vendor => src/vendor}/codemirror/addon/search/searchcursor.js (100%) rename {vendor => src/vendor}/codemirror/addon/selection/active-line.js (100%) rename {vendor => src/vendor}/codemirror/keymap/emacs.js (100%) rename {vendor => src/vendor}/codemirror/keymap/sublime.js (100%) rename {vendor => src/vendor}/codemirror/keymap/vim.js (100%) rename {vendor => src/vendor}/codemirror/lib/codemirror.css (100%) rename {vendor => src/vendor}/codemirror/lib/codemirror.js (100%) rename {vendor => src/vendor}/codemirror/mode/css/css.js (100%) rename {vendor => src/vendor}/codemirror/mode/javascript/javascript.js (100%) rename {vendor => src/vendor}/codemirror/mode/stylus/stylus.js (100%) rename {vendor => src/vendor}/db-to-cloud/LICENSE (100%) rename {vendor => src/vendor}/db-to-cloud/README.md (100%) rename {vendor => src/vendor}/db-to-cloud/db-to-cloud.js (100%) rename {vendor => src/vendor}/draggable-list/LICENSE (100%) rename {vendor => src/vendor}/draggable-list/README.md (100%) rename {vendor => src/vendor}/draggable-list/draggable-list.iife.js (100%) rename {vendor => src/vendor}/jsonlint/LICENSE (100%) rename {vendor => src/vendor}/jsonlint/README.md (100%) rename {vendor => src/vendor}/jsonlint/jsonlint.js (100%) rename {vendor => src/vendor}/less/LICENSE (100%) rename {vendor => src/vendor}/less/README.md (100%) rename {vendor => src/vendor}/less/less.min.js (100%) rename {vendor => src/vendor}/lz-string-unsafe/LICENSE (100%) rename {vendor => src/vendor}/lz-string-unsafe/README.md (100%) rename {vendor => src/vendor}/lz-string-unsafe/lz-string-unsafe.min.js (100%) rename {vendor => src/vendor}/stylelint-bundle/LICENSE (100%) rename {vendor => src/vendor}/stylelint-bundle/README.md (100%) rename {vendor => src/vendor}/stylelint-bundle/stylelint-bundle.min.js (100%) rename {vendor => src/vendor}/stylus-lang-bundle/LICENSE (100%) rename {vendor => src/vendor}/stylus-lang-bundle/README.md (100%) rename {vendor => src/vendor}/stylus-lang-bundle/stylus-renderer.min.js (100%) rename {vendor => src/vendor}/usercss-meta/LICENSE (100%) rename {vendor => src/vendor}/usercss-meta/README.md (100%) rename {vendor => src/vendor}/usercss-meta/usercss-meta.js (100%) rename {vendor => src/vendor}/webext-launch-web-auth-flow/LICENSE (100%) rename {vendor => src/vendor}/webext-launch-web-auth-flow/README.md (100%) rename {vendor => src/vendor}/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js (100%) diff --git a/.types.d.ts b/src/.types.d.ts similarity index 100% rename from .types.d.ts rename to src/.types.d.ts diff --git a/_locales/ar/messages.json b/src/_locales/ar/messages.json similarity index 100% rename from _locales/ar/messages.json rename to src/_locales/ar/messages.json diff --git a/_locales/bg/messages.json b/src/_locales/bg/messages.json similarity index 100% rename from _locales/bg/messages.json rename to src/_locales/bg/messages.json diff --git a/_locales/cs/messages.json b/src/_locales/cs/messages.json similarity index 100% rename from _locales/cs/messages.json rename to src/_locales/cs/messages.json diff --git a/_locales/da/messages.json b/src/_locales/da/messages.json similarity index 100% rename from _locales/da/messages.json rename to src/_locales/da/messages.json diff --git a/_locales/de/messages.json b/src/_locales/de/messages.json similarity index 100% rename from _locales/de/messages.json rename to src/_locales/de/messages.json diff --git a/_locales/el/messages.json b/src/_locales/el/messages.json similarity index 100% rename from _locales/el/messages.json rename to src/_locales/el/messages.json diff --git a/_locales/en/messages.json b/src/_locales/en/messages.json similarity index 100% rename from _locales/en/messages.json rename to src/_locales/en/messages.json diff --git a/_locales/en_GB/messages.json b/src/_locales/en_GB/messages.json similarity index 100% rename from _locales/en_GB/messages.json rename to src/_locales/en_GB/messages.json diff --git a/_locales/es/messages.json b/src/_locales/es/messages.json similarity index 100% rename from _locales/es/messages.json rename to src/_locales/es/messages.json diff --git a/_locales/es_419/messages.json b/src/_locales/es_419/messages.json similarity index 100% rename from _locales/es_419/messages.json rename to src/_locales/es_419/messages.json diff --git a/_locales/et/messages.json b/src/_locales/et/messages.json similarity index 100% rename from _locales/et/messages.json rename to src/_locales/et/messages.json diff --git a/_locales/fa/messages.json b/src/_locales/fa/messages.json similarity index 100% rename from _locales/fa/messages.json rename to src/_locales/fa/messages.json diff --git a/_locales/fi/messages.json b/src/_locales/fi/messages.json similarity index 100% rename from _locales/fi/messages.json rename to src/_locales/fi/messages.json diff --git a/_locales/fr/messages.json b/src/_locales/fr/messages.json similarity index 100% rename from _locales/fr/messages.json rename to src/_locales/fr/messages.json diff --git a/_locales/he/messages.json b/src/_locales/he/messages.json similarity index 100% rename from _locales/he/messages.json rename to src/_locales/he/messages.json diff --git a/_locales/hu/messages.json b/src/_locales/hu/messages.json similarity index 100% rename from _locales/hu/messages.json rename to src/_locales/hu/messages.json diff --git a/_locales/it/messages.json b/src/_locales/it/messages.json similarity index 100% rename from _locales/it/messages.json rename to src/_locales/it/messages.json diff --git a/_locales/ja/messages.json b/src/_locales/ja/messages.json similarity index 100% rename from _locales/ja/messages.json rename to src/_locales/ja/messages.json diff --git a/_locales/ko/messages.json b/src/_locales/ko/messages.json similarity index 100% rename from _locales/ko/messages.json rename to src/_locales/ko/messages.json diff --git a/_locales/lv/messages.json b/src/_locales/lv/messages.json similarity index 100% rename from _locales/lv/messages.json rename to src/_locales/lv/messages.json diff --git a/_locales/nl/messages.json b/src/_locales/nl/messages.json similarity index 100% rename from _locales/nl/messages.json rename to src/_locales/nl/messages.json diff --git a/_locales/pl/messages.json b/src/_locales/pl/messages.json similarity index 100% rename from _locales/pl/messages.json rename to src/_locales/pl/messages.json diff --git a/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json similarity index 100% rename from _locales/pt_BR/messages.json rename to src/_locales/pt_BR/messages.json diff --git a/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json similarity index 100% rename from _locales/pt_PT/messages.json rename to src/_locales/pt_PT/messages.json diff --git a/_locales/ro/messages.json b/src/_locales/ro/messages.json similarity index 100% rename from _locales/ro/messages.json rename to src/_locales/ro/messages.json diff --git a/_locales/ru/messages.json b/src/_locales/ru/messages.json similarity index 100% rename from _locales/ru/messages.json rename to src/_locales/ru/messages.json diff --git a/_locales/sr/messages.json b/src/_locales/sr/messages.json similarity index 100% rename from _locales/sr/messages.json rename to src/_locales/sr/messages.json diff --git a/_locales/sv/messages.json b/src/_locales/sv/messages.json similarity index 100% rename from _locales/sv/messages.json rename to src/_locales/sv/messages.json diff --git a/_locales/te/messages.json b/src/_locales/te/messages.json similarity index 100% rename from _locales/te/messages.json rename to src/_locales/te/messages.json diff --git a/_locales/tr/messages.json b/src/_locales/tr/messages.json similarity index 100% rename from _locales/tr/messages.json rename to src/_locales/tr/messages.json diff --git a/_locales/uk/messages.json b/src/_locales/uk/messages.json similarity index 100% rename from _locales/uk/messages.json rename to src/_locales/uk/messages.json diff --git a/_locales/vi/messages.json b/src/_locales/vi/messages.json similarity index 100% rename from _locales/vi/messages.json rename to src/_locales/vi/messages.json diff --git a/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json similarity index 100% rename from _locales/zh_CN/messages.json rename to src/_locales/zh_CN/messages.json diff --git a/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json similarity index 100% rename from _locales/zh_TW/messages.json rename to src/_locales/zh_TW/messages.json diff --git a/background/background-worker.js b/src/background/background-worker.js similarity index 100% rename from background/background-worker.js rename to src/background/background-worker.js diff --git a/background/background.js b/src/background/background.js similarity index 100% rename from background/background.js rename to src/background/background.js diff --git a/background/bg-prefs.js b/src/background/bg-prefs.js similarity index 100% rename from background/bg-prefs.js rename to src/background/bg-prefs.js diff --git a/background/browser-cmd-hotkeys.js b/src/background/browser-cmd-hotkeys.js similarity index 100% rename from background/browser-cmd-hotkeys.js rename to src/background/browser-cmd-hotkeys.js diff --git a/background/color-scheme.js b/src/background/color-scheme.js similarity index 100% rename from background/color-scheme.js rename to src/background/color-scheme.js diff --git a/background/common.js b/src/background/common.js similarity index 100% rename from background/common.js rename to src/background/common.js diff --git a/background/content-scripts.js b/src/background/content-scripts.js similarity index 100% rename from background/content-scripts.js rename to src/background/content-scripts.js diff --git a/background/context-menus.js b/src/background/context-menus.js similarity index 100% rename from background/context-menus.js rename to src/background/context-menus.js diff --git a/background/db-chrome-storage.js b/src/background/db-chrome-storage.js similarity index 100% rename from background/db-chrome-storage.js rename to src/background/db-chrome-storage.js diff --git a/background/db.js b/src/background/db.js similarity index 100% rename from background/db.js rename to src/background/db.js diff --git a/background/icon-manager.js b/src/background/icon-manager.js similarity index 100% rename from background/icon-manager.js rename to src/background/icon-manager.js diff --git a/background/navigation-manager.js b/src/background/navigation-manager.js similarity index 100% rename from background/navigation-manager.js rename to src/background/navigation-manager.js diff --git a/background/style-manager.js b/src/background/style-manager.js similarity index 100% rename from background/style-manager.js rename to src/background/style-manager.js diff --git a/background/style-search-db.js b/src/background/style-search-db.js similarity index 100% rename from background/style-search-db.js rename to src/background/style-search-db.js diff --git a/background/style-via-api.js b/src/background/style-via-api.js similarity index 100% rename from background/style-via-api.js rename to src/background/style-via-api.js diff --git a/background/style-via-webrequest.js b/src/background/style-via-webrequest.js similarity index 100% rename from background/style-via-webrequest.js rename to src/background/style-via-webrequest.js diff --git a/background/sync-manager.js b/src/background/sync-manager.js similarity index 100% rename from background/sync-manager.js rename to src/background/sync-manager.js diff --git a/background/tab-manager.js b/src/background/tab-manager.js similarity index 100% rename from background/tab-manager.js rename to src/background/tab-manager.js diff --git a/background/tab-util.js b/src/background/tab-util.js similarity index 100% rename from background/tab-util.js rename to src/background/tab-util.js diff --git a/background/token-manager.js b/src/background/token-manager.js similarity index 100% rename from background/token-manager.js rename to src/background/token-manager.js diff --git a/background/update-manager.js b/src/background/update-manager.js similarity index 100% rename from background/update-manager.js rename to src/background/update-manager.js diff --git a/background/usercss-install-helper.js b/src/background/usercss-install-helper.js similarity index 100% rename from background/usercss-install-helper.js rename to src/background/usercss-install-helper.js diff --git a/background/usercss-manager.js b/src/background/usercss-manager.js similarity index 100% rename from background/usercss-manager.js rename to src/background/usercss-manager.js diff --git a/background/uso-api.js b/src/background/uso-api.js similarity index 100% rename from background/uso-api.js rename to src/background/uso-api.js diff --git a/background/usw-api.js b/src/background/usw-api.js similarity index 100% rename from background/usw-api.js rename to src/background/usw-api.js diff --git a/content/apply.js b/src/content/apply.js similarity index 100% rename from content/apply.js rename to src/content/apply.js diff --git a/content/install-hook-greasyfork.js b/src/content/install-hook-greasyfork.js similarity index 100% rename from content/install-hook-greasyfork.js rename to src/content/install-hook-greasyfork.js diff --git a/content/install-hook-usercss.js b/src/content/install-hook-usercss.js similarity index 100% rename from content/install-hook-usercss.js rename to src/content/install-hook-usercss.js diff --git a/content/install-hook-userstyles.js b/src/content/install-hook-userstyles.js similarity index 100% rename from content/install-hook-userstyles.js rename to src/content/install-hook-userstyles.js diff --git a/content/install-hook-userstylesworld.js b/src/content/install-hook-userstylesworld.js similarity index 100% rename from content/install-hook-userstylesworld.js rename to src/content/install-hook-userstylesworld.js diff --git a/content/style-injector.js b/src/content/style-injector.js similarity index 100% rename from content/style-injector.js rename to src/content/style-injector.js diff --git a/css/global-dark.css b/src/css/global-dark.css similarity index 100% rename from css/global-dark.css rename to src/css/global-dark.css diff --git a/css/global.css b/src/css/global.css similarity index 100% rename from css/global.css rename to src/css/global.css diff --git a/css/icons.ttf b/src/css/icons.ttf similarity index 100% rename from css/icons.ttf rename to src/css/icons.ttf diff --git a/css/spinner.css b/src/css/spinner.css similarity index 100% rename from css/spinner.css rename to src/css/spinner.css diff --git a/edit.html b/src/edit.html similarity index 100% rename from edit.html rename to src/edit.html diff --git a/edit/autocomplete.js b/src/edit/autocomplete.js similarity index 100% rename from edit/autocomplete.js rename to src/edit/autocomplete.js diff --git a/edit/base.js b/src/edit/base.js similarity index 100% rename from edit/base.js rename to src/edit/base.js diff --git a/edit/beautify.js b/src/edit/beautify.js similarity index 100% rename from edit/beautify.js rename to src/edit/beautify.js diff --git a/edit/codemirror-default.css b/src/edit/codemirror-default.css similarity index 100% rename from edit/codemirror-default.css rename to src/edit/codemirror-default.css diff --git a/edit/codemirror-default.js b/src/edit/codemirror-default.js similarity index 100% rename from edit/codemirror-default.js rename to src/edit/codemirror-default.js diff --git a/edit/codemirror-factory.js b/src/edit/codemirror-factory.js similarity index 100% rename from edit/codemirror-factory.js rename to src/edit/codemirror-factory.js diff --git a/edit/codemirror-themes.js b/src/edit/codemirror-themes.js similarity index 100% rename from edit/codemirror-themes.js rename to src/edit/codemirror-themes.js diff --git a/src/edit/colorpicker-helper.js b/src/edit/colorpicker-helper.js new file mode 100644 index 00000000000..88b9e1d9ad8 --- /dev/null +++ b/src/edit/colorpicker-helper.js @@ -0,0 +1,59 @@ +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import '/js/color/color-view'; +import CodeMirror from 'codemirror'; +import {extraKeys} from './codemirror-default'; +import cmFactory from './codemirror-factory'; + +const {defaults, commands} = CodeMirror; + +prefs.subscribe('editor.colorpicker.hotkey', (id, hotkey) => { + commands.colorpicker = invokeColorpicker; + for (const key in extraKeys) { + if (extraKeys[key] === 'colorpicker') { + delete extraKeys[key]; + break; + } + } + if (hotkey) { + extraKeys[hotkey] = 'colorpicker'; + } +}, true); + +prefs.subscribe('editor.colorpicker', (id, enabled) => { + const keyName = prefs.get('editor.colorpicker.hotkey'); + defaults.colorpicker = enabled; + if (enabled) { + if (keyName) { + commands.colorpicker = invokeColorpicker; + extraKeys[keyName] = 'colorpicker'; + } + defaults.colorpicker = { + tooltip: t('colorpickerTooltip'), + popup: { + tooltipForSwitcher: t('colorpickerSwitchFormatTooltip'), + paletteLine: t('numberedLine'), + paletteHint: t('colorpickerPaletteHint'), + hexUppercase: prefs.get('editor.colorpicker.hexUppercase'), + embedderCallback: state => { + ['hexUppercase', 'color'] + .filter(name => state[name] !== prefs.get('editor.colorpicker.' + name)) + .forEach(name => prefs.set('editor.colorpicker.' + name, state[name])); + }, + get maxHeight() { + return prefs.get('editor.colorpicker.maxHeight'); + }, + set maxHeight(h) { + prefs.set('editor.colorpicker.maxHeight', h); + }, + }, + }; + } else { + delete extraKeys[keyName]; + } + cmFactory.globalSetOption('colorpicker', defaults.colorpicker); +}, true); + +function invokeColorpicker(cm) { + cm.state.colorpicker.openPopup(prefs.get('editor.colorpicker.color')); +} diff --git a/src/edit/dirty-reporter.js b/src/edit/dirty-reporter.js new file mode 100644 index 00000000000..0e5aebbfd83 --- /dev/null +++ b/src/edit/dirty-reporter.js @@ -0,0 +1,91 @@ +export default function DirtyReporter() { + const data = new Map(); + const listeners = new Set(); + const dataListeners = new Set(); + const notifyChange = wasDirty => { + const isDirty = data.size > 0; + const flipped = isDirty !== wasDirty; + if (flipped) { + listeners.forEach(cb => cb(isDirty)); + } + if (flipped || isDirty) { + dataListeners.forEach(cb => cb(isDirty)); + } + }; + /** @namespace DirtyReporter */ + return { + add(obj, value) { + const wasDirty = data.size > 0; + const saved = data.get(obj); + if (!saved) { + data.set(obj, {type: 'add', newValue: value}); + } else if (saved.type === 'remove') { + if (saved.savedValue === value) { + data.delete(obj); + } else { + saved.newValue = value; + saved.type = 'modify'; + } + } else { + return; + } + notifyChange(wasDirty); + }, + clear(id) { + if (data.size && ( + id ? data.delete(id) + : (data.clear(), true) + )) { + notifyChange(true); + } + }, + has(key) { + return data.has(key); + }, + isDirty() { + return data.size > 0; + }, + modify(obj, oldValue, newValue) { + const wasDirty = data.size > 0; + const saved = data.get(obj); + if (!saved) { + if (oldValue !== newValue) { + data.set(obj, {type: 'modify', savedValue: oldValue, newValue}); + } else { + return; + } + } else if (saved.type === 'modify') { + if (saved.savedValue === newValue) { + data.delete(obj); + } else { + saved.newValue = newValue; + } + } else if (saved.type === 'add') { + saved.newValue = newValue; + } else { + return; + } + notifyChange(wasDirty); + }, + onChange(cb, add = true) { + listeners[add ? 'add' : 'delete'](cb); + }, + onDataChange(cb, add = true) { + dataListeners[add ? 'add' : 'delete'](cb); + }, + remove(obj, value) { + const wasDirty = data.size > 0; + const saved = data.get(obj); + if (!saved) { + data.set(obj, {type: 'remove', savedValue: value}); + } else if (saved.type === 'add') { + data.delete(obj); + } else if (saved.type === 'modify') { + saved.type = 'remove'; + } else { + return; + } + notifyChange(wasDirty); + }, + }; +} diff --git a/edit/drafts.js b/src/edit/drafts.js similarity index 100% rename from edit/drafts.js rename to src/edit/drafts.js diff --git a/edit/edit.css b/src/edit/edit.css similarity index 100% rename from edit/edit.css rename to src/edit/edit.css diff --git a/edit/edit.js b/src/edit/edit.js similarity index 100% rename from edit/edit.js rename to src/edit/edit.js diff --git a/src/edit/editor-header.js b/src/edit/editor-header.js new file mode 100644 index 00000000000..c09bd5315df --- /dev/null +++ b/src/edit/editor-header.js @@ -0,0 +1,81 @@ +import {$, $$, setInputValue, setupLivePrefs} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import CodeMirror from 'codemirror'; +import {extraKeys} from './codemirror-default'; +import {initBeautifyButton} from './beautify'; +import editor from './editor'; + +export default function EditorHeader() { + initBeautifyButton($('#beautify')); + initNameArea(); + setupLivePrefs(); + window.on('load', () => { + prefs.subscribe('editor.keyMap', showHotkeyInTooltip, true); + window.on('showHotkeyInTooltip', showHotkeyInTooltip); + }, {once: true}); + for (const el of $$('#header details')) { + el.on('contextmenu', peekDetails); + } +} + +function findKeyForCommand(command, map) { + if (typeof map === 'string') map = CodeMirror.keyMap[map]; + let key = Object.keys(map).find(k => map[k] === command); + if (key) { + return key; + } + for (const ft of Array.isArray(map.fallthrough) ? map.fallthrough : [map.fallthrough]) { + key = ft && findKeyForCommand(command, ft); + if (key) { + return key; + } + } + return ''; +} + +function initNameArea() { + const nameEl = $('#name'); + const resetEl = $('#reset-name'); + const isCustomName = editor.style.updateUrl || editor.isUsercss; + editor.nameTarget = isCustomName ? 'customName' : 'name'; + nameEl.placeholder = t(editor.isUsercss ? 'usercssEditorNamePlaceholder' : 'styleMissingName'); + nameEl.title = isCustomName ? t('customNameHint') : ''; + nameEl.on('input', () => { + editor.updateName(true); + resetEl.hidden = !editor.style.customName; + }); + resetEl.hidden = !editor.style.customName; + resetEl.onclick = () => { + setInputValue(nameEl, editor.style.name); + editor.style.customName = null; // to delete it from db + resetEl.hidden = true; + }; + const enabledEl = $('#enabled'); + enabledEl.onchange = () => editor.updateEnabledness(enabledEl.checked); +} + +async function peekDetails(evt) { + evt.preventDefault(); + this.open = true; + while (this.matches(':hover, :active')) { + await new Promise(cb => setTimeout(cb, 500)); + await new Promise(cb => this.on('mouseleave', cb, {once: true})); + } + this.open = false; +} + +function showHotkeyInTooltip(_, mapName = prefs.get('editor.keyMap')) { + for (const el of $$('[data-hotkey-tooltip]')) { + if (el._hotkeyTooltipKeyMap !== mapName) { + el._hotkeyTooltipKeyMap = mapName; + const title = el._hotkeyTooltipTitle = el._hotkeyTooltipTitle || el.title; + const cmd = el.dataset.hotkeyTooltip; + const key = cmd[0] === '=' ? cmd.slice(1) : + findKeyForCommand(cmd, mapName) || + findKeyForCommand(cmd, extraKeys); + const newTitle = title + (title && key ? '\n' : '') + (key || ''); + if (el.title !== newTitle) el.title = newTitle; + } + } +} diff --git a/edit/editor-worker.js b/src/edit/editor-worker.js similarity index 100% rename from edit/editor-worker.js rename to src/edit/editor-worker.js diff --git a/src/edit/editor.js b/src/edit/editor.js new file mode 100644 index 00000000000..605d1bbcec4 --- /dev/null +++ b/src/edit/editor.js @@ -0,0 +1,233 @@ +import {$, $create} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import {clipString, debounce, deepEqual, fetchText, mapObj, sessionStore} from '/js/toolbox'; +import DirtyReporter from './dirty-reporter'; + +const CM_THEMES = {}; +const dirty = DirtyReporter(); +const mqCompact = matchMedia('(max-width: 850px)'); +/** @type {Set} */ +const regexps = new Set(); +const toc = []; + +let style; +let wasDirty = false; + +/** + * @type Editor + * @namespace Editor + */ +const editor = { + dirty, + isUsercss: false, + isWindowed: false, + livePreviewLazy: cb => debounce(cb, prefs.get('editor.livePreview.delay') * 1000), + mqCompact, + /** @type {'customName'|'name'} */ + nameTarget: 'name', + ppDemo: { + stylus: 'https://stylus-lang.com/try.html', + less: 'https://lesscss.org/less-preview/', + }, + regexps, + saving: false, + scrollInfo: {}, + get style() { + return style; + }, + set style(val) { + style = val; + }, + + applyScrollInfo(cm, si = (editor.scrollInfo.cms || [])[0]) { + if (si && si.sel) { + const bmOpts = {sublimeBookmark: true, clearWhenEmpty: false}; // copied from sublime.js + const bms = cm.state.sublimeBookmarks = []; + for (const b of si.bookmarks) bms.push(cm.markText(b.from, b.to, bmOpts)); + cm.setSelections(...si.sel, {scroll: false}); + Object.assign(cm.display.scroller, si.scroll); // for source editor + Object.assign(cm.doc, si.scroll); // for sectioned editor + } + }, + + cancel: () => location.assign('/manage.html'), + + makeScrollInfo() { + return { + scrollY: window.scrollY, + cms: editor.getEditors().map(cm => /** @namespace EditorScrollInfo */({ + bookmarks: (cm.state.sublimeBookmarks || []).map(b => b.find()), + focus: cm.hasFocus(), + height: cm.display.wrapper.style.height.replace('100vh', ''), + parentHeight: cm.display.wrapper.parentElement.offsetHeight, + scroll: mapObj(cm.doc, null, ['scrollLeft', 'scrollTop']), + sel: [cm.doc.sel.ranges, cm.doc.sel.primIndex], + })), + }; + }, + + async save() { + if (dirty.isDirty()) { + editor.saving = true; + await editor.saveImpl(); + } + }, + + toggleRegexp(el, type) { + let hide; + if (type === 'regexp') { + el.on('input', validateRegexp); + if (regexps.add(el).size === 1) hide = false; + } else { + el.setCustomValidity(''); + el.off('input', validateRegexp); + if (regexps.delete(el) && !regexps.size) hide = true; + } + if (hide != null) $('#testRE').hidden = hide; + }, + + toggleStyle(enabled = !style.enabled) { + $('#enabled').checked = enabled; + editor.updateEnabledness(enabled); + }, + + updateClass() { + $.rootCL.toggle('is-new-style', !editor.style.id); + }, + + updateDirty() { + const isDirty = dirty.isDirty(); + if (wasDirty !== isDirty) { + wasDirty = isDirty; + document.body.classList.toggle('dirty', isDirty); + $('#save-button').disabled = !isDirty; + } + editor.updateTitle(); + }, + + updateEnabledness(enabled) { + dirty.modify('enabled', style.enabled, enabled); + style.enabled = enabled; + editor.updateLivePreview(); + }, + + updateName(isUserInput) { + if (!editor) return; + if (isUserInput) { + const {value} = $('#name'); + dirty.modify('name', style[editor.nameTarget] || style.name, value); + style[editor.nameTarget] = value; + } + editor.updateTitle(); + }, + + async updateTheme(name) { + const el = $('#cm-theme'); + const { + [name]: css = await fetchText(`/vendor/codemirror/theme/${name}.css`).catch(() => ''), + } = CM_THEMES; + if (!css) { + name = 'default'; + prefs.set('editor.theme', name); + } + el.dataset.theme = name; + el.textContent = css; + }, + + updateTitle(isDirty = editor.dirty.isDirty()) { + const {customName, name} = editor.style; + document.title = `${ + isDirty ? '* ' : '' + }${ + customName || name || t('styleMissingName') + } - Stylus`; // the suffix enables external utilities to process our windows e.g. pin on top + }, + + updateToc(added) { + const {sections} = editor; + if (!toc.el) { + toc.el = $('#toc'); + toc.elDetails = toc.el.closest('details'); + toc.title = $('#toc-title').dataset; + } + let num = 0; + for (const sec of sections) num += !sec.removed; + if ((+toc.title.num || 1) !== num) { + if (num > 1) { + toc.title.num = num; + } else { + delete toc.title.num; + } + } + if (!toc.elDetails.open) return; + if (!added) added = sections; + const first = sections.indexOf(added[0]); + const elFirst = toc.el.children[first]; + if (first >= 0 && (!added.focus || !elFirst)) { + for (let el = elFirst, i = first; i < sections.length; i++) { + const entry = sections[i].tocEntry; + if (!deepEqual(entry, toc[i])) { + if (!el) el = toc.el.appendChild($create('li', {tabIndex: 0})); + el.tabIndex = entry.removed ? -1 : 0; + toc[i] = Object.assign({}, entry); + const s = el.textContent = clipString(entry.label) || ( + entry.target == null + ? t('appliesToEverything') + : clipString(entry.target) + (entry.numTargets > 1 ? ', ...' : '')); + if (s.length > 30) el.title = s; + } + el = el.nextElementSibling; + } + } + while (toc.length > sections.length) { + toc.el.lastElementChild.remove(); + toc.length--; + } + if (added.focus) { + const cls = 'current'; + const old = $('.' + cls, toc.el); + const el = elFirst || toc.el.children[first]; + if (old && old !== el) old.classList.remove(cls); + el.classList.add(cls); + } + }, + + useSavedStyle(newStyle) { + if (style.id !== newStyle.id) { + history.replaceState({}, '', `?id=${newStyle.id}`); + } + sessionStore.justEditedStyleId = newStyle.id; + Object.assign(style, newStyle); + editor.updateClass(); + editor.updateMeta(); + }, +}; + +function toggleCompact(mq) { + $.rootCL.toggle('compact-layout', mq.matches); +} + +export function failRegexp(r) { + try { + new RegExp(r); + r = ''; + } catch (err) { + r = err.message.split('/:').pop().trim(); + } + return r; +} + +function validateRegexp({target: el}) { + let err = failRegexp(el.value); + if (err) err = t('styleBadRegexp') + '\n' + err; + if (el.title !== err) { + el.title = err; + el.setCustomValidity(err); + } +} + +mqCompact.on('change', toggleCompact); +toggleCompact(mqCompact); + +export default editor; diff --git a/edit/embedded-popup.js b/src/edit/embedded-popup.js similarity index 100% rename from edit/embedded-popup.js rename to src/edit/embedded-popup.js diff --git a/edit/global-search.css b/src/edit/global-search.css similarity index 100% rename from edit/global-search.css rename to src/edit/global-search.css diff --git a/edit/global-search.js b/src/edit/global-search.js similarity index 100% rename from edit/global-search.js rename to src/edit/global-search.js diff --git a/src/edit/index.js b/src/edit/index.js new file mode 100644 index 00000000000..8ad6eb47405 --- /dev/null +++ b/src/edit/index.js @@ -0,0 +1,140 @@ +import {$, $$, $create, important} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import '/css/global.css'; +import '/css/global-dark.css'; +import 'codemirror/lib/codemirror.css'; +import 'codemirror/addon/comment/comment'; +import 'codemirror/addon/dialog/dialog'; +import 'codemirror/addon/dialog/dialog.css'; +import 'codemirror/addon/edit/closebrackets'; +import 'codemirror/addon/edit/matchbrackets'; +import 'codemirror/addon/fold/brace-fold'; +import 'codemirror/addon/fold/comment-fold'; +import 'codemirror/addon/fold/foldcode'; +import 'codemirror/addon/fold/foldgutter'; +import 'codemirror/addon/fold/foldgutter.css'; +import 'codemirror/addon/fold/indent-fold'; +import 'codemirror/addon/hint/anyword-hint'; +import 'codemirror/addon/hint/css-hint'; +import 'codemirror/addon/hint/show-hint'; +import 'codemirror/addon/hint/show-hint.css'; +import 'codemirror/addon/lint/lint'; +import 'codemirror/addon/lint/lint.css'; +import 'codemirror/addon/scroll/annotatescrollbar'; +import 'codemirror/addon/search/matchesonscrollbar'; +import 'codemirror/addon/search/matchesonscrollbar.css'; +import 'codemirror/addon/search/searchcursor'; +import 'codemirror/addon/selection/active-line'; +import 'codemirror/keymap/emacs'; +import 'codemirror/keymap/sublime'; +import 'codemirror/keymap/vim'; +import 'codemirror/mode/css/css'; +import 'codemirror/mode/stylus/stylus'; +import '/vendor-overwrites/codemirror-addon/match-highlighter.js'; +import '/js/color/color-picker.css'; +import './codemirror-default.css'; +import './edit.css'; +import './settings.css'; +import Autocomplete from './autocomplete'; +import Drafts from './drafts'; +import editor from './editor'; +import EditorHeader from './editor-header'; +import GlobalSearch from './global-search'; +import {showLintHelp} from './linter-dialogs'; +import linterMan from './linter-manager'; +import * as regexpTester from './regexp-tester'; +import SectionsEditor from './sections-editor'; +import SourceEditor from './source-editor'; +import styleReady from './style-ready'; +import './colorpicker-helper'; +import './live-preview'; +import './on-msg-extension'; +import './settings'; +import './usw-integration'; +import './windowed-mode'; + +t.body(); + +styleReady.then(async () => { + EditorHeader(); + await (editor.isUsercss ? SourceEditor : SectionsEditor)(); + + editor.dirty.onChange(editor.updateDirty); + prefs.subscribe('editor.linter', () => linterMan.run()); + + // enabling after init to prevent flash of validation failure on an empty name + $('#name').required = !editor.isUsercss; + $('#save-button').onclick = editor.save; + $('#cancel-button').onclick = editor.cancel; + $('#lint-help').onclick = showLintHelp; + $('#testRE').hidden = !editor.style.sections.some(({regexps: r}) => r && r.length); + $('#testRE').onclick = () => require(['/edit/regexp-tester.css'], () => regexpTester.toggle(true)); + const elSec = $('#sections-list'); + const elToc = $('#toc'); + const moDetails = new MutationObserver(([{target: sec}]) => { + if (!sec.open) return; + if (sec === elSec) editor.updateToc(); + const el = sec.lastElementChild; + const s = el.style; + const x2 = sec.getBoundingClientRect().left + el.getBoundingClientRect().width; + if (x2 > innerWidth - 30) s.right = '0'; + else if (s.right) s.removeProperty('right'); + }); + // editor.toc.expanded pref isn't saved in compact-layout so prefs.subscribe won't work + if (elSec.open) editor.updateToc(); + // and we also toggle `open` directly in other places e.g. in detectLayout() + for (const el of $$('#details-wrapper > details')) { + moDetails.observe(el, {attributes: true, attributeFilter: ['open']}); + } + elToc.onclick = e => + editor.jumpToEditor([].indexOf.call(elToc.children, e.target)); + + Autocomplete(); + Drafts(); + GlobalSearch(); +}); + +styleReady.then(async () => { + // Set up mini-header on scroll + const {isUsercss} = editor; + const el = $create({ + style: important(` + top: 0; + height: 1px; + position: absolute; + visibility: hidden; + `), + }); + const scroller = isUsercss ? $('.CodeMirror-scroll') : document.body; + const xoRoot = isUsercss ? scroller : undefined; + const xo = new IntersectionObserver(onScrolled, {root: xoRoot}); + const elInfo = $('h1 a'); + scroller.appendChild(el); + onCompactToggled(editor.mqCompact); + editor.mqCompact.on('change', onCompactToggled); + + /** @param {MediaQueryList} mq */ + function onCompactToggled(mq) { + for (const el of $$('details[data-pref]')) { + el.open = mq.matches ? false : + el.classList.contains('ignore-pref') ? el.open : + prefs.get(el.dataset.pref); + } + if (mq.matches) { + xo.observe(el); + $('#basic-info-name').after(elInfo); + } else { + xo.disconnect(); + $('h1').append(elInfo); + } + } + + /** @param {IntersectionObserverEntry[]} entries */ + function onScrolled(entries) { + const h = $('#header'); + const sticky = !entries.pop().intersectionRatio; + if (!isUsercss) scroller.style.paddingTop = sticky ? h.offsetHeight + 'px' : ''; + h.classList.toggle('sticky', sticky); + } +}); diff --git a/edit/linter-dialogs.js b/src/edit/linter-dialogs.js similarity index 100% rename from edit/linter-dialogs.js rename to src/edit/linter-dialogs.js diff --git a/edit/linter-manager.js b/src/edit/linter-manager.js similarity index 100% rename from edit/linter-manager.js rename to src/edit/linter-manager.js diff --git a/src/edit/live-preview.js b/src/edit/live-preview.js new file mode 100644 index 00000000000..226b3dadcee --- /dev/null +++ b/src/edit/live-preview.js @@ -0,0 +1,84 @@ +import {$} from '/js/dom'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {UCD} from '/js/toolbox'; +import editor from './editor'; + +const ID = 'editor.livePreview'; +let errPos; +let el; +let data; +let port; +let enabled = prefs.get(ID); + +prefs.subscribe(ID, (key, value) => { + if (!value) { + if (port) { + port.disconnect(); + port = null; + } + } else if (data && data.id && (data.enabled || editor.dirty.has('enabled'))) { + createPreviewer(); + updatePreviewer(data); + } + enabled = value; +}); + +editor.livePreview = newData => { + if (!port) { + if (!enabled + || !newData.id // not saved + || !newData.enabled && data && !data.enabled // disabled both before and now + || !editor.dirty.isDirty()) { + return; + } + createPreviewer(); + } + data = newData; + updatePreviewer(data); +}; + +function createPreviewer() { + port = chrome.runtime.connect({name: 'livePreview:' + editor.style.id}); + port.onDisconnect.addListener(() => (port = null)); + el = $('#preview-errors'); + el.onclick = showError; +} + +function showError() { + if (errPos) { + const cm = editor.getEditors()[0]; + cm.setCursor(errPos); + cm.focus(); + } +} + +async function updatePreviewer(data) { + try { + await API.styles.preview(data); + el.hidden = true; + } catch (err) { + const ucd = data[UCD]; + const pp = ucd && ucd.preprocessor; + const shift = err._varLines + 1 || 0; + errPos = pp && err.line && err.column + ? {line: err.line - shift, ch: err.column - 1} + : err.index; + if (Array.isArray(err)) { + err = err.map((e, a, b) => !(a = e.message) ? e : ((b = e.context)) ? `${a} in ${b}` : a).join('\n'); + } else { + err = err.message || `${err}`; + } + if (errPos >= 0) { + // FIXME: this would fail if editors[0].getValue() !== data.sourceCode + errPos = editor.getEditors()[0].posFromIndex(errPos); + } else if (pp === 'stylus' && (errPos = err.match(/^\w+:(\d+):(\d+)(?:\n.+)+\s+(.+)/))) { + err = errPos[3]; + errPos = {line: errPos[1] - shift, ch: errPos[2] - 1}; + } + el.title = + el.firstChild.textContent = (errPos ? `${errPos.line + 1}:${errPos.ch + 1} ` : '') + err; + el.lastChild.hidden = !(el.lastChild.href = editor.ppDemo[pp]); + el.hidden = false; + } +} diff --git a/edit/moz-section-finder.js b/src/edit/moz-section-finder.js similarity index 100% rename from edit/moz-section-finder.js rename to src/edit/moz-section-finder.js diff --git a/edit/moz-section-widget.js b/src/edit/moz-section-widget.js similarity index 100% rename from edit/moz-section-widget.js rename to src/edit/moz-section-widget.js diff --git a/src/edit/on-msg-extension.js b/src/edit/on-msg-extension.js new file mode 100644 index 00000000000..d89afebdbed --- /dev/null +++ b/src/edit/on-msg-extension.js @@ -0,0 +1,54 @@ +import {API, onExtension} from '/js/msg'; +import {closeCurrentTab} from '/js/toolbox'; +import editor from './editor'; + +onExtension(request => { + const {style} = request; + switch (request.method) { + case 'styleUpdated': + if (editor.style.id === style.id) { + handleExternalUpdate(request); + } + break; + case 'styleDeleted': + if (editor.style.id === style.id) { + closeCurrentTab(); + } + break; + } +}); + +async function handleExternalUpdate({style, reason}) { + if (reason === 'editPreview' || + reason === 'editPreviewEnd') { + return; + } + if (reason === 'editSave' && editor.saving) { + editor.saving = false; + return; + } + if (reason === 'toggle') { + if (editor.dirty.isDirty()) { + editor.toggleStyle(style.enabled); + // updateLivePreview is called by toggleStyle + } else { + Object.assign(editor.style, style); + editor.updateLivePreview(); + } + editor.updateMeta(); + return; + } + style = await API.styles.get(style.id); + if (reason === 'config') { + for (const key in editor.style) if (!(key in style)) delete editor.style[key]; + delete style.sourceCode; + delete style.sections; + delete style.name; + delete style.enabled; + Object.assign(editor.style, style); + editor.updateLivePreview(); + } else { + await editor.replaceStyle(style); + } + window.dispatchEvent(new Event('styleSettings')); +} diff --git a/edit/regexp-tester.css b/src/edit/regexp-tester.css similarity index 100% rename from edit/regexp-tester.css rename to src/edit/regexp-tester.css diff --git a/edit/regexp-tester.js b/src/edit/regexp-tester.js similarity index 100% rename from edit/regexp-tester.js rename to src/edit/regexp-tester.js diff --git a/edit/sections-editor-section.js b/src/edit/sections-editor-section.js similarity index 100% rename from edit/sections-editor-section.js rename to src/edit/sections-editor-section.js diff --git a/edit/sections-editor.js b/src/edit/sections-editor.js similarity index 100% rename from edit/sections-editor.js rename to src/edit/sections-editor.js diff --git a/edit/settings.css b/src/edit/settings.css similarity index 100% rename from edit/settings.css rename to src/edit/settings.css diff --git a/edit/settings.js b/src/edit/settings.js similarity index 100% rename from edit/settings.js rename to src/edit/settings.js diff --git a/edit/show-keymap-help.js b/src/edit/show-keymap-help.js similarity index 100% rename from edit/show-keymap-help.js rename to src/edit/show-keymap-help.js diff --git a/edit/source-editor.js b/src/edit/source-editor.js similarity index 100% rename from edit/source-editor.js rename to src/edit/source-editor.js diff --git a/src/edit/style-ready.js b/src/edit/style-ready.js new file mode 100644 index 00000000000..6a580d39675 --- /dev/null +++ b/src/edit/style-ready.js @@ -0,0 +1,60 @@ +import {$} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {MozDocMapper} from '/js/sections-util'; +import {chromeSync} from '/js/storage-util'; +import {clipString, sessionStore, tryURL, UCD} from '/js/toolbox'; +import editor from './editor'; + +let params = new URLSearchParams(location.search); +let id = +params.get('id'); + +export default Promise.all([ + Promise.all([ + id ? API.styles.get(id) : undefined, + prefs.ready.then(() => editor.updateTheme(prefs.get('editor.theme'))), + ]).then(loadStyle), + id && API.data.get('editorScrollInfo' + id).then(si => { + editor.scrollInfo = si || {}; + }), + new Promise(t.body), +]); + +async function loadStyle([ + style = { + id: id = null, // resetting the non-existent id + name: makeName(params), + enabled: true, + sections: [ + MozDocMapper.toSection([...params], {code: ''}), + ], + }, +]) { + // switching the mode here to show the correct page ASAP, usually before DOMContentLoaded + const isUC = Boolean(style[UCD] || !id && prefs.get('newStyleAsUsercss')); + Object.assign(editor, /** @namespace Editor */ { + style, + isUsercss: isUC, + template: isUC && !id && chromeSync.getLZValue(chromeSync.LZ_KEY.usercssTemplate), // promise + }); + editor.updateClass(); + editor.updateTitle(false); + $.rootCL.add(isUC ? 'usercss' : 'sectioned'); + sessionStore.justEditedStyleId = id || ''; + // no such style so let's clear the invalid URL parameters + if (id === null) { + params.delete('id'); + params = `${params}`; + history.replaceState({}, '', location.pathname + (params ? '?' : '') + params); + } +} + +function makeName(params) { + const prefix = tryURL(params.get('url-prefix')); + const name = params.get('name') || prefix.hostname; + const p = prefix.pathname || '/'; + return name + ? name + (p === '/' ? '' : clipString(p.replace(/\.(html?|aspx?|cgi|php)$/, ''))) + : params.get('domain') || '?'; +} diff --git a/src/edit/unload.js b/src/edit/unload.js new file mode 100644 index 00000000000..a9e1de4e053 --- /dev/null +++ b/src/edit/unload.js @@ -0,0 +1,41 @@ +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {sessionStore} from '/js/toolbox'; +import editor from './editor'; + +window.on('beforeunload', e => { + let pos; + if (editor.isWindowed && + document.visibilityState === 'visible' && + prefs.get('openEditInWindow') && + screenX !== -32000 && // Chrome uses this value for minimized windows + ( // only if not maximized + screenX > 0 || outerWidth < screen.availWidth || + screenY > 0 || outerHeight < screen.availHeight || + screenX <= -10 || outerWidth >= screen.availWidth + 10 || + screenY <= -10 || outerHeight >= screen.availHeight + 10 + ) + ) { + pos = { + left: screenX, + top: screenY, + width: outerWidth, + height: outerHeight, + }; + prefs.set('windowPosition', pos); + } + sessionStore.windowPos = JSON.stringify(pos || {}); + API.data.set('editorScrollInfo' + editor.style.id, editor.makeScrollInfo()); + const activeElement = document.activeElement; + if (activeElement) { + // blurring triggers 'change' or 'input' event if needed + activeElement.blur(); + // refocus if unloading was canceled + setTimeout(() => activeElement.focus()); + } + if (editor.dirty.isDirty()) { + // neither confirm() nor custom messages work in modern browsers but just in case + e.returnValue = t('styleChangesNotSaved'); + } +}); diff --git a/edit/usw-integration.js b/src/edit/usw-integration.js similarity index 100% rename from edit/usw-integration.js rename to src/edit/usw-integration.js diff --git a/edit/util.js b/src/edit/util.js similarity index 100% rename from edit/util.js rename to src/edit/util.js diff --git a/src/edit/windowed-mode.js b/src/edit/windowed-mode.js new file mode 100644 index 00000000000..87502f08403 --- /dev/null +++ b/src/edit/windowed-mode.js @@ -0,0 +1,52 @@ +import * as prefs from '/js/prefs'; +import {FIREFOX, getOwnTab, sessionStore, tryJSONparse} from '/js/toolbox'; +import editor from './editor'; + +let ownTabId; +if (chrome.windows) { + initWindowedMode(); + const pos = tryJSONparse(sessionStore.windowPos); + delete sessionStore.windowPos; + // resize the window on 'undo close' + if (pos && pos.left != null) { + chrome.windows.update(chrome.windows.WINDOW_ID_CURRENT, pos); + } +} + +getOwnTab().then(tab => { + ownTabId = tab.id; + if (sessionStore['manageStylesHistory' + ownTabId] === location.href) { + editor.cancel = () => history.back(); + } +}); + +async function initWindowedMode() { + chrome.tabs.onAttached.addListener(onTabAttached); + // Chrome 96+ bug: the type is 'app' for a window that was restored via Ctrl-Shift-T + const isSimple = ['app', 'popup'].includes((await browser.windows.getCurrent()).type); + if (isSimple) require(['/edit/embedded-popup']); + editor.isWindowed = isSimple || ( + history.length === 1 && + await prefs.ready && prefs.get('openEditInWindow') && + (await browser.windows.getAll()).length > 1 && + (await browser.tabs.query({currentWindow: true})).length === 1 + ); +} + +async function onTabAttached(tabId, info) { + if (tabId !== ownTabId) { + return; + } + if (info.newPosition !== 0) { + prefs.set('openEditInWindow', false); + return; + } + const win = await browser.windows.get(info.newWindowId, {populate: true}); + // If there's only one tab in this window, it's been dragged to new window + const openEditInWindow = win.tabs.length === 1; + // FF-only because Chrome retardedly resets the size during dragging + if (openEditInWindow && FIREFOX) { + chrome.windows.update(info.newWindowId, prefs.get('windowPosition')); + } + prefs.set('openEditInWindow', openEditInWindow); +} diff --git a/images/eyedropper/16px.png b/src/images/eyedropper/16px.png similarity index 100% rename from images/eyedropper/16px.png rename to src/images/eyedropper/16px.png diff --git a/images/eyedropper/32px.png b/src/images/eyedropper/32px.png similarity index 100% rename from images/eyedropper/32px.png rename to src/images/eyedropper/32px.png diff --git a/images/eyedropper/README.md b/src/images/eyedropper/README.md similarity index 100% rename from images/eyedropper/README.md rename to src/images/eyedropper/README.md diff --git a/images/icon/128.png b/src/images/icon/128.png similarity index 100% rename from images/icon/128.png rename to src/images/icon/128.png diff --git a/images/icon/16.png b/src/images/icon/16.png similarity index 100% rename from images/icon/16.png rename to src/images/icon/16.png diff --git a/images/icon/16w.png b/src/images/icon/16w.png similarity index 100% rename from images/icon/16w.png rename to src/images/icon/16w.png diff --git a/images/icon/16x.png b/src/images/icon/16x.png similarity index 100% rename from images/icon/16x.png rename to src/images/icon/16x.png diff --git a/images/icon/19.png b/src/images/icon/19.png similarity index 100% rename from images/icon/19.png rename to src/images/icon/19.png diff --git a/images/icon/19w.png b/src/images/icon/19w.png similarity index 100% rename from images/icon/19w.png rename to src/images/icon/19w.png diff --git a/images/icon/19x.png b/src/images/icon/19x.png similarity index 100% rename from images/icon/19x.png rename to src/images/icon/19x.png diff --git a/images/icon/32.png b/src/images/icon/32.png similarity index 100% rename from images/icon/32.png rename to src/images/icon/32.png diff --git a/images/icon/32w.png b/src/images/icon/32w.png similarity index 100% rename from images/icon/32w.png rename to src/images/icon/32w.png diff --git a/images/icon/32x.png b/src/images/icon/32x.png similarity index 100% rename from images/icon/32x.png rename to src/images/icon/32x.png diff --git a/images/icon/38.png b/src/images/icon/38.png similarity index 100% rename from images/icon/38.png rename to src/images/icon/38.png diff --git a/images/icon/38w.png b/src/images/icon/38w.png similarity index 100% rename from images/icon/38w.png rename to src/images/icon/38w.png diff --git a/images/icon/38x.png b/src/images/icon/38x.png similarity index 100% rename from images/icon/38x.png rename to src/images/icon/38x.png diff --git a/images/icon/48.png b/src/images/icon/48.png similarity index 100% rename from images/icon/48.png rename to src/images/icon/48.png diff --git a/images/icon/light/16.png b/src/images/icon/light/16.png similarity index 100% rename from images/icon/light/16.png rename to src/images/icon/light/16.png diff --git a/images/icon/light/16w.png b/src/images/icon/light/16w.png similarity index 100% rename from images/icon/light/16w.png rename to src/images/icon/light/16w.png diff --git a/images/icon/light/16x.png b/src/images/icon/light/16x.png similarity index 100% rename from images/icon/light/16x.png rename to src/images/icon/light/16x.png diff --git a/images/icon/light/19.png b/src/images/icon/light/19.png similarity index 100% rename from images/icon/light/19.png rename to src/images/icon/light/19.png diff --git a/images/icon/light/19w.png b/src/images/icon/light/19w.png similarity index 100% rename from images/icon/light/19w.png rename to src/images/icon/light/19w.png diff --git a/images/icon/light/19x.png b/src/images/icon/light/19x.png similarity index 100% rename from images/icon/light/19x.png rename to src/images/icon/light/19x.png diff --git a/images/icon/light/32.png b/src/images/icon/light/32.png similarity index 100% rename from images/icon/light/32.png rename to src/images/icon/light/32.png diff --git a/images/icon/light/32w.png b/src/images/icon/light/32w.png similarity index 100% rename from images/icon/light/32w.png rename to src/images/icon/light/32w.png diff --git a/images/icon/light/32x.png b/src/images/icon/light/32x.png similarity index 100% rename from images/icon/light/32x.png rename to src/images/icon/light/32x.png diff --git a/images/icon/light/38.png b/src/images/icon/light/38.png similarity index 100% rename from images/icon/light/38.png rename to src/images/icon/light/38.png diff --git a/images/icon/light/38w.png b/src/images/icon/light/38w.png similarity index 100% rename from images/icon/light/38w.png rename to src/images/icon/light/38w.png diff --git a/images/icon/light/38x.png b/src/images/icon/light/38x.png similarity index 100% rename from images/icon/light/38x.png rename to src/images/icon/light/38x.png diff --git a/images/icons/check1.svg b/src/images/icons/check1.svg similarity index 100% rename from images/icons/check1.svg rename to src/images/icons/check1.svg diff --git a/images/icons/check2.svg b/src/images/icons/check2.svg similarity index 100% rename from images/icons/check2.svg rename to src/images/icons/check2.svg diff --git a/images/icons/checked.svg b/src/images/icons/checked.svg similarity index 100% rename from images/icons/checked.svg rename to src/images/icons/checked.svg diff --git a/images/icons/close.svg b/src/images/icons/close.svg similarity index 100% rename from images/icons/close.svg rename to src/images/icons/close.svg diff --git a/images/icons/config.svg b/src/images/icons/config.svg similarity index 100% rename from images/icons/config.svg rename to src/images/icons/config.svg diff --git a/images/icons/edit.svg b/src/images/icons/edit.svg similarity index 100% rename from images/icons/edit.svg rename to src/images/icons/edit.svg diff --git a/images/icons/empty.svg b/src/images/icons/empty.svg similarity index 100% rename from images/icons/empty.svg rename to src/images/icons/empty.svg diff --git a/images/icons/external.svg b/src/images/icons/external.svg similarity index 100% rename from images/icons/external.svg rename to src/images/icons/external.svg diff --git a/images/icons/info.svg b/src/images/icons/info.svg similarity index 100% rename from images/icons/info.svg rename to src/images/icons/info.svg diff --git a/images/icons/install.svg b/src/images/icons/install.svg similarity index 100% rename from images/icons/install.svg rename to src/images/icons/install.svg diff --git a/images/icons/log.svg b/src/images/icons/log.svg similarity index 100% rename from images/icons/log.svg rename to src/images/icons/log.svg diff --git a/images/icons/menu.svg b/src/images/icons/menu.svg similarity index 100% rename from images/icons/menu.svg rename to src/images/icons/menu.svg diff --git a/images/icons/minus.svg b/src/images/icons/minus.svg similarity index 100% rename from images/icons/minus.svg rename to src/images/icons/minus.svg diff --git a/images/icons/plus.svg b/src/images/icons/plus.svg similarity index 100% rename from images/icons/plus.svg rename to src/images/icons/plus.svg diff --git a/images/icons/reorder.svg b/src/images/icons/reorder.svg similarity index 100% rename from images/icons/reorder.svg rename to src/images/icons/reorder.svg diff --git a/images/icons/select-arrow.svg b/src/images/icons/select-arrow.svg similarity index 100% rename from images/icons/select-arrow.svg rename to src/images/icons/select-arrow.svg diff --git a/images/icons/sort-down.svg b/src/images/icons/sort-down.svg similarity index 100% rename from images/icons/sort-down.svg rename to src/images/icons/sort-down.svg diff --git a/images/icons/undo.svg b/src/images/icons/undo.svg similarity index 100% rename from images/icons/undo.svg rename to src/images/icons/undo.svg diff --git a/images/icons/update-check.svg b/src/images/icons/update-check.svg similarity index 100% rename from images/icons/update-check.svg rename to src/images/icons/update-check.svg diff --git a/images/icons/usercss.svg b/src/images/icons/usercss.svg similarity index 100% rename from images/icons/usercss.svg rename to src/images/icons/usercss.svg diff --git a/images/icons/v.svg b/src/images/icons/v.svg similarity index 100% rename from images/icons/v.svg rename to src/images/icons/v.svg diff --git a/injection-order/injection-order.css b/src/injection-order/injection-order.css similarity index 100% rename from injection-order/injection-order.css rename to src/injection-order/injection-order.css diff --git a/injection-order/injection-order.js b/src/injection-order/injection-order.js similarity index 100% rename from injection-order/injection-order.js rename to src/injection-order/injection-order.js diff --git a/install-usercss.html b/src/install-usercss.html similarity index 100% rename from install-usercss.html rename to src/install-usercss.html diff --git a/install-usercss/install-usercss.css b/src/install-usercss/install-usercss.css similarity index 100% rename from install-usercss/install-usercss.css rename to src/install-usercss/install-usercss.css diff --git a/install-usercss/install-usercss.js b/src/install-usercss/install-usercss.js similarity index 100% rename from install-usercss/install-usercss.js rename to src/install-usercss/install-usercss.js diff --git a/install-usercss/preinit.js b/src/install-usercss/preinit.js similarity index 100% rename from install-usercss/preinit.js rename to src/install-usercss/preinit.js diff --git a/js/browser.js b/src/js/browser.js similarity index 100% rename from js/browser.js rename to src/js/browser.js diff --git a/js/cmpver.js b/src/js/cmpver.js similarity index 100% rename from js/cmpver.js rename to src/js/cmpver.js diff --git a/js/color/LICENSE b/src/js/color/LICENSE similarity index 100% rename from js/color/LICENSE rename to src/js/color/LICENSE diff --git a/js/color/README.md b/src/js/color/README.md similarity index 100% rename from js/color/README.md rename to src/js/color/README.md diff --git a/js/color/color-converter.js b/src/js/color/color-converter.js similarity index 100% rename from js/color/color-converter.js rename to src/js/color/color-converter.js diff --git a/js/color/color-mimicry.js b/src/js/color/color-mimicry.js similarity index 100% rename from js/color/color-mimicry.js rename to src/js/color/color-mimicry.js diff --git a/js/color/color-picker.css b/src/js/color/color-picker.css similarity index 100% rename from js/color/color-picker.css rename to src/js/color/color-picker.css diff --git a/js/color/color-picker.js b/src/js/color/color-picker.js similarity index 100% rename from js/color/color-picker.js rename to src/js/color/color-picker.js diff --git a/js/color/color-view.js b/src/js/color/color-view.js similarity index 100% rename from js/color/color-view.js rename to src/js/color/color-view.js diff --git a/js/csslint/LICENSE b/src/js/csslint/LICENSE similarity index 100% rename from js/csslint/LICENSE rename to src/js/csslint/LICENSE diff --git a/js/csslint/README.md b/src/js/csslint/README.md similarity index 100% rename from js/csslint/README.md rename to src/js/csslint/README.md diff --git a/js/csslint/csslint.js b/src/js/csslint/csslint.js similarity index 100% rename from js/csslint/csslint.js rename to src/js/csslint/csslint.js diff --git a/js/csslint/parserlib-base.js b/src/js/csslint/parserlib-base.js similarity index 100% rename from js/csslint/parserlib-base.js rename to src/js/csslint/parserlib-base.js diff --git a/js/csslint/parserlib.js b/src/js/csslint/parserlib.js similarity index 100% rename from js/csslint/parserlib.js rename to src/js/csslint/parserlib.js diff --git a/js/dlg/config-dialog.css b/src/js/dlg/config-dialog.css similarity index 100% rename from js/dlg/config-dialog.css rename to src/js/dlg/config-dialog.css diff --git a/js/dlg/config-dialog.js b/src/js/dlg/config-dialog.js similarity index 100% rename from js/dlg/config-dialog.js rename to src/js/dlg/config-dialog.js diff --git a/js/dlg/message-box.css b/src/js/dlg/message-box.css similarity index 100% rename from js/dlg/message-box.css rename to src/js/dlg/message-box.css diff --git a/js/dlg/message-box.js b/src/js/dlg/message-box.js similarity index 100% rename from js/dlg/message-box.js rename to src/js/dlg/message-box.js diff --git a/src/js/dom-base.js b/src/js/dom-base.js new file mode 100644 index 00000000000..de0aa0942f8 --- /dev/null +++ b/src/js/dom-base.js @@ -0,0 +1,178 @@ +import {hasOwn} from './toolbox'; + +Object.assign(EventTarget.prototype, { + on: addEventListener, + off: removeEventListener, +}); + +// TODO: export directly +$.root = document.documentElement; +$.rootCL = $.root.classList; + +export const dom = {}; + +// Makes the focus outline appear on keyboard tabbing, but not on mouse clicks. +export const focusA11y = { + // last event's focusedViaClick + lastFocusedViaClick: false, + get: el => el && el.dataset.focusedViaClick != null, + toggle: (el, state) => el && toggleDataset(el, 'focusedViaClick', state), + // to avoid a full layout recalc due to changes on body/root + // we modify the closest focusable element (like input or button or anything with tabindex=0) + closest(el) { + let labelSeen; + for (; el; el = el.parentElement) { + if (el.localName === 'label' && el.control && !labelSeen) { + el = el.control; + labelSeen = true; + } + if (el.tabIndex >= 0) return el; + } + }, +}; + +/** + * Autoloads message-box.js + */ +export let messageBoxProxy = new Proxy({}, { + get(_, name) { + return (...args) => Promise.all([ + import('./dlg/message-box'), + require(['/js/dlg/message-box.css']), + ]).then(([m]) => (messageBoxProxy = m.default)[name](...args)); + }, +}); + +export function $(selector, base) { + // we have ids with . like #manage.onlyEnabled which looks like #id.class + // so since getElementById is superfast we'll try it anyway + const byId = !base && selector.startsWith('#') && document.getElementById(selector.slice(1)); + return byId || (base || document).querySelector(selector); +} + +export function $$(selector, base = document) { + return [...base.querySelectorAll(selector)]; +} + +export function $isTextInput(el = {}) { + return el.localName === 'textarea' || + el.localName === 'input' && /^(text|search|number)$/.test(el.type); +} + +export function $remove(selector, base = document) { + const el = selector && typeof selector === 'string' ? $(selector, base) : selector; + if (el) { + el.remove(); + } +} + +export function $$remove(selector, base = document) { + for (const el of base.querySelectorAll(selector)) { + el.remove(); + } +} + +/** + * All parameters are omittable e.g. (), (sel), (props, children), (children) + * All parts of `selector` are optional, tag is 'div' by default. + * `children` is a string (textContent) or Node or array of text/nodes + * `properties` is an object with some special keys: + tag: string, default 'div' + appendChild: element/string or an array of elements/strings + attributes: {'html-case-name': val, ...} via setAttribute + dataset: {camelCaseName: val, ...} via Object.assign + 'data-attr-name': val via setAttribute + 'attr:name': val via setAttribute without prefix + anythingElse: val via el[key] assignment + */ +export function $create(selector = 'div', properties, children) { + let tag, opt; + if (typeof selector === 'string') { + if (Array.isArray(properties) || + properties instanceof Node || + typeof properties !== 'object' && children == null) { + opt = {}; + children = properties; + } else { + opt = properties || {}; + children = children || opt.appendChild; + } + const idStart = (selector.indexOf('#') + 1 || selector.length + 1) - 1; + const classStart = (selector.indexOf('.') + 1 || selector.length + 1) - 1; + const id = selector.slice(idStart + 1, classStart); + if (id) { + opt.id = id; + } + const cls = selector.slice(classStart + 1); + if (cls) opt.className = cls.replace(/\./g, ' '); + tag = selector.slice(0, Math.min(idStart, classStart)); + } else if (Array.isArray(selector)) { + tag = 'div'; + opt = {}; + children = selector; + } else { + opt = selector; + tag = opt.tag; + children = opt.appendChild || properties; + } + const element = + tag === 'fragment' ? document.createDocumentFragment() : + document.createElement(tag || 'div'); + for (const child of Array.isArray(children) ? children : [children]) { + if (child) { + element.appendChild(child instanceof Node ? child : document.createTextNode(child)); + } + } + for (const key in opt) { + if (!hasOwn(opt, key)) continue; + const val = opt[key]; + switch (key) { + case 'dataset': + Object.assign(element.dataset, val); + break; + case 'attributes': + if (val) Object.entries(val).forEach(attr => element.setAttribute(...attr)); + break; + case 'style': { + const t = typeof val; + if (t === 'string') element.style.cssText = val; + if (t === 'object') Object.assign(element.style, val); + break; + } + case 'tag': + case 'appendChild': + break; + default: { + if (key.startsWith('attr:')) element.setAttribute(key.slice(5), val); + else if (key.startsWith('data-')) element.setAttribute(key, val); + else element[key] = val; + } + } + } + return element; +} + +export function $createLink(href = '', content) { + const opt = { + tag: 'a', + target: '_blank', + rel: 'noopener', + }; + if (typeof href === 'object') { + Object.assign(opt, href); + } else { + opt.href = href; + } + opt.appendChild = opt.appendChild || content; + return $create(opt); +} + +export function toggleDataset(el, prop, state) { + if (!el) return; + const wasEnabled = el.dataset[prop] != null; // avoids mutating DOM unnecessarily + if (state) { + if (!wasEnabled) el.dataset[prop] = ''; + } else { + if (wasEnabled) delete el.dataset[prop]; + } +} diff --git a/js/dom-on-load.js b/src/js/dom-on-load.js similarity index 100% rename from js/dom-on-load.js rename to src/js/dom-on-load.js diff --git a/src/js/dom-util.js b/src/js/dom-util.js new file mode 100644 index 00000000000..72703fb3505 --- /dev/null +++ b/src/js/dom-util.js @@ -0,0 +1,216 @@ +import {$, $$, $create, focusA11y, toggleDataset} from './dom-base'; +import * as prefs from './prefs'; + +/** + * @param {HTMLElement} el + * @param {string} [cls] - class name that defines or starts an animation + * @param [removeExtraClasses] - class names to remove at animation end in the *same* paint frame, + * which is needed in e.g. Firefox as it may call resolve() in the next frame + * @returns {Promise} + */ +export function animateElement(el, cls = 'highlight', ...removeExtraClasses) { + return !el ? Promise.resolve(el) : new Promise(resolve => { + let onDone = () => { + el.classList.remove(cls, ...removeExtraClasses); + onDone = null; + resolve(); + }; + requestAnimationFrame(() => { + if (onDone) { + const style = getComputedStyle(el); + if (style.animationName === 'none' || !parseFloat(style.animationDuration)) { + el.off('animationend', onDone); + onDone(); + } + } + }); + el.on('animationend', onDone, {once: true}); + el.classList.add(cls); + }); +} + +export function getEventKeyName(e, letterAsCode) { + const mods = + (e.shiftKey ? 'Shift-' : '') + + (e.ctrlKey ? 'Ctrl-' : '') + + (e.altKey ? 'Alt-' : '') + + (e.metaKey ? 'Meta-' : ''); + return `${ + mods === e.key + '-' ? '' : mods + }${ + e.key + ? !e.key[1] && letterAsCode ? e.code // KeyC + : e.key[1] ? e.key // Esc + : e.key.toUpperCase() // C, Shift-C (single letters we use uppercase for consistency) + : 'Mouse' + ('LMR'[e.button] || e.button) + }`; +} + +export function important(str) { + return str.replace(/;/g, '!important;'); +} + +/** + * Switches to the next/previous keyboard-focusable element. + * Doesn't check `visibility` or `display` via getComputedStyle for simplicity. + * @param {HTMLElement} rootElement + * @param {Number} step - for exmaple 1 or -1 (or 0 to focus the first focusable el in the box) + * @returns {HTMLElement|false|undefined} - + * HTMLElement: focus changed, + * false: focus unchanged, + * undefined: nothing to focus + */ +export function moveFocus(rootElement, step) { + const elements = [...rootElement.getElementsByTagName('*')]; + const activeEl = document.activeElement; + const activeIndex = step ? Math.max(step < 0 ? 0 : -1, elements.indexOf(activeEl)) : -1; + const num = elements.length; + if (!step) step = 1; + for (let i = 1; i <= num; i++) { + const el = elements[(activeIndex + i * step + num) % num]; + if (!el.disabled && el.tabIndex >= 0 && el.getBoundingClientRect().width) { + el.focus(); + // suppress focus outline when invoked via click + toggleDataset(el, 'focusedViaClick', focusA11y.lastFocusedViaClick); + return activeEl !== el && el; + } + } +} + +/** + * Scrolls `window` or the closest parent with `class="scroller"` if the element is not visible, + * centering the element in the view + * @param {HTMLElement} element + * @param {number} [invalidMarginRatio] - for example, 0.10 will center the element if it's in the top/bottom 10% of the scroller + */ +export function scrollElementIntoView(element, {invalidMarginRatio = 0} = {}) { + // align to the top/bottom of the visible area if wasn't visible + if (!element.parentNode) return; + const {top, height} = element.getBoundingClientRect(); + const {top: parentTop, bottom: parentBottom} = element.parentNode.getBoundingClientRect(); + const windowHeight = window.innerHeight; + if (top < Math.max(parentTop, windowHeight * invalidMarginRatio) || + top > Math.min(parentBottom, windowHeight) - height - windowHeight * invalidMarginRatio) { + const scroller = element.closest('.scroller') || window; + scroller.scrollBy(0, top - (scroller.clientHeight || windowHeight) / 2 + height); + } +} + +export function setInputValue(input, value) { + input.focus(); + input.select(); + // using execCommand to add to the input's undo history + document.execCommand(value ? 'insertText' : 'delete', false, value); + // some versions of Firefox ignore execCommand + if (input.value !== value) { + input.value = value; + input.dispatchEvent(new Event('input', {bubbles: true})); + } +} + +/** + * Accepts an array of pref names (values are fetched via prefs.get) + * or an element inside which to look for elements with known pref ids + * and establishes a two-way connection between the document elements and the actual prefs + */ +export function setupLivePrefs(ids) { + let init = true; + // getElementsByTagName is cached so it's much faster than calling querySelector for each id + const all = (ids instanceof Element ? ids : document).getElementsByTagName('*'); + ids = Array.isArray(ids) ? [...ids] : prefs.knownKeys.filter(id => id in all); + prefs.subscribe(ids, updateElement, true); + init = false; + function onChange() { + if (this.checkValidity() && (this.type !== 'radio' || this.checked)) { + prefs.set(this.id || this.name, getValue(this)); + } + } + function getValue(el) { + const type = el.dataset.valueType || el.type; + return type === 'checkbox' ? el.checked : + type === 'number' ? parseFloat(el.value) : + el.value; + } + function isSame(el, oldValue, value) { + return el.type === 'radio' ? el.checked === (oldValue === value) : + el.localName === 'select' && typeof value === 'boolean' && oldValue === `${value}` || + oldValue === value; + } + function updateElement(id, value) { + const byId = all[id]; + const els = byId && byId.id ? [byId] : document.getElementsByName(id); + if (!els[0]) { + prefs.unsubscribe(id, updateElement); + return; + } + for (const el of els) { + const oldValue = getValue(el); + const diff = !isSame(el, oldValue, value); + if ((init || diff) && el.type === 'select-one' && el.classList.contains('fit-width')) { + fitSelectBox(el, value, init); /* global fitSelectBox */// manage/render.js + } else if (diff) { + if (el.type === 'radio') { + el.checked = value === oldValue; + } else if (el.type === 'checkbox') { + el.checked = value; + } else { + el.value = value; + } + el.dispatchEvent(new Event('change', {bubbles: true})); + } + if (init) el.on('change', onChange); + } + } +} + +/** @param {string|Node} parent - selector or DOM node */ +export async function showSpinner(parent) { + await require(['/css/spinner.css']); + parent = parent instanceof Node ? parent : $(parent); + return parent.appendChild($create('.lds-spinner', + new Array(12).fill($create('div')).map(e => e.cloneNode()))); +} + +/** + * @param {string} selector - beware of $ quirks with `#dotted.id` that won't work with $$ + * @param {Object} [opt] + * @param {function(HTMLElement[]):boolean} [opt.recur] - called on each match until stopOnDomReady, + you can also return `false` to disconnect the observer + * @param {boolean} [opt.stopOnDomReady] - stop observing on DOM ready + * @returns {Promise} - resolves on first match + */ +export function waitForSelector(selector, {recur, stopOnDomReady = true} = {}) { + let el = $(selector); + let elems; + return el && (!recur || recur(elems = $$(selector)) === false) + ? Promise.resolve(el) + : new Promise(resolve => { + new MutationObserver((mutations, observer) => { + if (!el) el = $(selector); + if (!el) return; + if (!recur || + callRecur(mutations) === false || + stopOnDomReady && document.readyState === 'complete') { + observer.disconnect(); + } + if (resolve) { + resolve(el); + resolve = null; + } + }).observe(document, {childList: true, subtree: true}); + function isMatching(n) { + return n.tagName && (n.matches(selector) || n.firstElementChild && $(selector, n)); + } + function callRecur([m0, m1]) { + // Checking addedNodes if only 1 MutationRecord to skip simple mutations quickly + if (m1 || (m0 = m0.addedNodes)[3] || [].some.call(m0, isMatching)) { + const all = $$(selector); // Using one $$ call instead of ~100 calls for each node + const added = !elems ? all : all.filter(el => !elems.includes(el)); + if (added.length) { + elems = all; + return recur(added); + } + } + } + }); +} diff --git a/js/dom.js b/src/js/dom.js similarity index 100% rename from js/dom.js rename to src/js/dom.js diff --git a/js/header-resizer.js b/src/js/header-resizer.js similarity index 100% rename from js/header-resizer.js rename to src/js/header-resizer.js diff --git a/js/localization.js b/src/js/localization.js similarity index 100% rename from js/localization.js rename to src/js/localization.js diff --git a/js/meta-parser.js b/src/js/meta-parser.js similarity index 100% rename from js/meta-parser.js rename to src/js/meta-parser.js diff --git a/js/moz-parser.js b/src/js/moz-parser.js similarity index 100% rename from js/moz-parser.js rename to src/js/moz-parser.js diff --git a/js/msg.js b/src/js/msg.js similarity index 100% rename from js/msg.js rename to src/js/msg.js diff --git a/js/popup-get-styles.js b/src/js/popup-get-styles.js similarity index 100% rename from js/popup-get-styles.js rename to src/js/popup-get-styles.js diff --git a/js/prefs.js b/src/js/prefs.js similarity index 100% rename from js/prefs.js rename to src/js/prefs.js diff --git a/js/router.js b/src/js/router.js similarity index 100% rename from js/router.js rename to src/js/router.js diff --git a/js/sections-util.js b/src/js/sections-util.js similarity index 100% rename from js/sections-util.js rename to src/js/sections-util.js diff --git a/js/storage-util.js b/src/js/storage-util.js similarity index 100% rename from js/storage-util.js rename to src/js/storage-util.js diff --git a/js/themer.js b/src/js/themer.js similarity index 100% rename from js/themer.js rename to src/js/themer.js diff --git a/js/toolbox.js b/src/js/toolbox.js similarity index 100% rename from js/toolbox.js rename to src/js/toolbox.js diff --git a/js/usercss-compiler.js b/src/js/usercss-compiler.js similarity index 100% rename from js/usercss-compiler.js rename to src/js/usercss-compiler.js diff --git a/js/worker-util.js b/src/js/worker-util.js similarity index 100% rename from js/worker-util.js rename to src/js/worker-util.js diff --git a/manage.html b/src/manage.html similarity index 100% rename from manage.html rename to src/manage.html diff --git a/manage/events.js b/src/manage/events.js similarity index 100% rename from manage/events.js rename to src/manage/events.js diff --git a/manage/filters.js b/src/manage/filters.js similarity index 100% rename from manage/filters.js rename to src/manage/filters.js diff --git a/manage/import-export.js b/src/manage/import-export.js similarity index 100% rename from manage/import-export.js rename to src/manage/import-export.js diff --git a/manage/incremental-search.js b/src/manage/incremental-search.js similarity index 100% rename from manage/incremental-search.js rename to src/manage/incremental-search.js diff --git a/manage/manage-newui.css b/src/manage/manage-newui.css similarity index 100% rename from manage/manage-newui.css rename to src/manage/manage-newui.css diff --git a/manage/manage.css b/src/manage/manage.css similarity index 100% rename from manage/manage.css rename to src/manage/manage.css diff --git a/manage/manage.js b/src/manage/manage.js similarity index 100% rename from manage/manage.js rename to src/manage/manage.js diff --git a/manage/render.js b/src/manage/render.js similarity index 100% rename from manage/render.js rename to src/manage/render.js diff --git a/manage/sorter.js b/src/manage/sorter.js similarity index 100% rename from manage/sorter.js rename to src/manage/sorter.js diff --git a/manage/updater-ui.js b/src/manage/updater-ui.js similarity index 100% rename from manage/updater-ui.js rename to src/manage/updater-ui.js diff --git a/manifest.json b/src/manifest.json similarity index 100% rename from manifest.json rename to src/manifest.json diff --git a/options.html b/src/options.html similarity index 100% rename from options.html rename to src/options.html diff --git a/options/onoffswitch.css b/src/options/onoffswitch.css similarity index 100% rename from options/onoffswitch.css rename to src/options/onoffswitch.css diff --git a/options/options-sync.js b/src/options/options-sync.js similarity index 100% rename from options/options-sync.js rename to src/options/options-sync.js diff --git a/options/options.css b/src/options/options.css similarity index 100% rename from options/options.css rename to src/options/options.css diff --git a/options/options.js b/src/options/options.js similarity index 100% rename from options/options.js rename to src/options/options.js diff --git a/popup.html b/src/popup.html similarity index 100% rename from popup.html rename to src/popup.html diff --git a/popup/events.js b/src/popup/events.js similarity index 100% rename from popup/events.js rename to src/popup/events.js diff --git a/popup/hotkeys.js b/src/popup/hotkeys.js similarity index 100% rename from popup/hotkeys.js rename to src/popup/hotkeys.js diff --git a/popup/popup.css b/src/popup/popup.css similarity index 100% rename from popup/popup.css rename to src/popup/popup.css diff --git a/popup/popup.js b/src/popup/popup.js similarity index 100% rename from popup/popup.js rename to src/popup/popup.js diff --git a/popup/search.css b/src/popup/search.css similarity index 100% rename from popup/search.css rename to src/popup/search.css diff --git a/popup/search.html b/src/popup/search.html similarity index 100% rename from popup/search.html rename to src/popup/search.html diff --git a/popup/search.js b/src/popup/search.js similarity index 100% rename from popup/search.js rename to src/popup/search.js diff --git a/vendor-overwrites/beautify/LICENSE b/src/vendor-overwrites/beautify/LICENSE similarity index 97% rename from vendor-overwrites/beautify/LICENSE rename to src/vendor-overwrites/beautify/LICENSE index 30878fd6923..d2b0f258bf1 100644 --- a/vendor-overwrites/beautify/LICENSE +++ b/src/vendor-overwrites/beautify/LICENSE @@ -1,34 +1,34 @@ -CSS Beautifier -Written by Harutyun Amirjanyan, (amirjanyan@gmail.com) -https://github.com/beautify-web/js-beautify - -Based on code initially developed by -Einar Lielmanis, -http://jsbeautifier.org/ - -https://github.com/beautify-web/js-beautify/blob/master/LICENSE - - -The MIT License (MIT) - -Copyright (c) 2007-2017 Einar Lielmanis, Liam Newman, and contributors. - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation files -(the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +CSS Beautifier +Written by Harutyun Amirjanyan, (amirjanyan@gmail.com) +https://github.com/beautify-web/js-beautify + +Based on code initially developed by +Einar Lielmanis, +http://jsbeautifier.org/ + +https://github.com/beautify-web/js-beautify/blob/master/LICENSE + + +The MIT License (MIT) + +Copyright (c) 2007-2017 Einar Lielmanis, Liam Newman, and contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor-overwrites/beautify/README.md b/src/vendor-overwrites/beautify/README.md similarity index 100% rename from vendor-overwrites/beautify/README.md rename to src/vendor-overwrites/beautify/README.md diff --git a/vendor-overwrites/beautify/beautify-css-mod.js b/src/vendor-overwrites/beautify/beautify-css-mod.js similarity index 100% rename from vendor-overwrites/beautify/beautify-css-mod.js rename to src/vendor-overwrites/beautify/beautify-css-mod.js diff --git a/vendor-overwrites/codemirror-addon/match-highlighter.js b/src/vendor-overwrites/codemirror-addon/match-highlighter.js similarity index 100% rename from vendor-overwrites/codemirror-addon/match-highlighter.js rename to src/vendor-overwrites/codemirror-addon/match-highlighter.js diff --git a/vendor/codemirror/LICENSE b/src/vendor/codemirror/LICENSE similarity index 100% rename from vendor/codemirror/LICENSE rename to src/vendor/codemirror/LICENSE diff --git a/vendor/codemirror/README.md b/src/vendor/codemirror/README.md similarity index 100% rename from vendor/codemirror/README.md rename to src/vendor/codemirror/README.md diff --git a/vendor/codemirror/addon/comment/comment.js b/src/vendor/codemirror/addon/comment/comment.js similarity index 100% rename from vendor/codemirror/addon/comment/comment.js rename to src/vendor/codemirror/addon/comment/comment.js diff --git a/vendor/codemirror/addon/dialog/dialog.css b/src/vendor/codemirror/addon/dialog/dialog.css similarity index 100% rename from vendor/codemirror/addon/dialog/dialog.css rename to src/vendor/codemirror/addon/dialog/dialog.css diff --git a/vendor/codemirror/addon/dialog/dialog.js b/src/vendor/codemirror/addon/dialog/dialog.js similarity index 100% rename from vendor/codemirror/addon/dialog/dialog.js rename to src/vendor/codemirror/addon/dialog/dialog.js diff --git a/vendor/codemirror/addon/edit/closebrackets.js b/src/vendor/codemirror/addon/edit/closebrackets.js similarity index 100% rename from vendor/codemirror/addon/edit/closebrackets.js rename to src/vendor/codemirror/addon/edit/closebrackets.js diff --git a/vendor/codemirror/addon/edit/matchbrackets.js b/src/vendor/codemirror/addon/edit/matchbrackets.js similarity index 100% rename from vendor/codemirror/addon/edit/matchbrackets.js rename to src/vendor/codemirror/addon/edit/matchbrackets.js diff --git a/vendor/codemirror/addon/fold/brace-fold.js b/src/vendor/codemirror/addon/fold/brace-fold.js similarity index 100% rename from vendor/codemirror/addon/fold/brace-fold.js rename to src/vendor/codemirror/addon/fold/brace-fold.js diff --git a/vendor/codemirror/addon/fold/comment-fold.js b/src/vendor/codemirror/addon/fold/comment-fold.js similarity index 100% rename from vendor/codemirror/addon/fold/comment-fold.js rename to src/vendor/codemirror/addon/fold/comment-fold.js diff --git a/vendor/codemirror/addon/fold/foldcode.js b/src/vendor/codemirror/addon/fold/foldcode.js similarity index 100% rename from vendor/codemirror/addon/fold/foldcode.js rename to src/vendor/codemirror/addon/fold/foldcode.js diff --git a/vendor/codemirror/addon/fold/foldgutter.css b/src/vendor/codemirror/addon/fold/foldgutter.css similarity index 100% rename from vendor/codemirror/addon/fold/foldgutter.css rename to src/vendor/codemirror/addon/fold/foldgutter.css diff --git a/vendor/codemirror/addon/fold/foldgutter.js b/src/vendor/codemirror/addon/fold/foldgutter.js similarity index 100% rename from vendor/codemirror/addon/fold/foldgutter.js rename to src/vendor/codemirror/addon/fold/foldgutter.js diff --git a/vendor/codemirror/addon/fold/indent-fold.js b/src/vendor/codemirror/addon/fold/indent-fold.js similarity index 100% rename from vendor/codemirror/addon/fold/indent-fold.js rename to src/vendor/codemirror/addon/fold/indent-fold.js diff --git a/vendor/codemirror/addon/hint/anyword-hint.js b/src/vendor/codemirror/addon/hint/anyword-hint.js similarity index 100% rename from vendor/codemirror/addon/hint/anyword-hint.js rename to src/vendor/codemirror/addon/hint/anyword-hint.js diff --git a/vendor/codemirror/addon/hint/css-hint.js b/src/vendor/codemirror/addon/hint/css-hint.js similarity index 100% rename from vendor/codemirror/addon/hint/css-hint.js rename to src/vendor/codemirror/addon/hint/css-hint.js diff --git a/vendor/codemirror/addon/hint/show-hint.css b/src/vendor/codemirror/addon/hint/show-hint.css similarity index 100% rename from vendor/codemirror/addon/hint/show-hint.css rename to src/vendor/codemirror/addon/hint/show-hint.css diff --git a/vendor/codemirror/addon/hint/show-hint.js b/src/vendor/codemirror/addon/hint/show-hint.js similarity index 100% rename from vendor/codemirror/addon/hint/show-hint.js rename to src/vendor/codemirror/addon/hint/show-hint.js diff --git a/vendor/codemirror/addon/lint/css-lint.js b/src/vendor/codemirror/addon/lint/css-lint.js similarity index 100% rename from vendor/codemirror/addon/lint/css-lint.js rename to src/vendor/codemirror/addon/lint/css-lint.js diff --git a/vendor/codemirror/addon/lint/json-lint.js b/src/vendor/codemirror/addon/lint/json-lint.js similarity index 100% rename from vendor/codemirror/addon/lint/json-lint.js rename to src/vendor/codemirror/addon/lint/json-lint.js diff --git a/vendor/codemirror/addon/lint/lint.css b/src/vendor/codemirror/addon/lint/lint.css similarity index 100% rename from vendor/codemirror/addon/lint/lint.css rename to src/vendor/codemirror/addon/lint/lint.css diff --git a/vendor/codemirror/addon/lint/lint.js b/src/vendor/codemirror/addon/lint/lint.js similarity index 100% rename from vendor/codemirror/addon/lint/lint.js rename to src/vendor/codemirror/addon/lint/lint.js diff --git a/vendor/codemirror/addon/scroll/annotatescrollbar.js b/src/vendor/codemirror/addon/scroll/annotatescrollbar.js similarity index 100% rename from vendor/codemirror/addon/scroll/annotatescrollbar.js rename to src/vendor/codemirror/addon/scroll/annotatescrollbar.js diff --git a/vendor/codemirror/addon/search/matchesonscrollbar.css b/src/vendor/codemirror/addon/search/matchesonscrollbar.css similarity index 100% rename from vendor/codemirror/addon/search/matchesonscrollbar.css rename to src/vendor/codemirror/addon/search/matchesonscrollbar.css diff --git a/vendor/codemirror/addon/search/matchesonscrollbar.js b/src/vendor/codemirror/addon/search/matchesonscrollbar.js similarity index 100% rename from vendor/codemirror/addon/search/matchesonscrollbar.js rename to src/vendor/codemirror/addon/search/matchesonscrollbar.js diff --git a/vendor/codemirror/addon/search/searchcursor.js b/src/vendor/codemirror/addon/search/searchcursor.js similarity index 100% rename from vendor/codemirror/addon/search/searchcursor.js rename to src/vendor/codemirror/addon/search/searchcursor.js diff --git a/vendor/codemirror/addon/selection/active-line.js b/src/vendor/codemirror/addon/selection/active-line.js similarity index 100% rename from vendor/codemirror/addon/selection/active-line.js rename to src/vendor/codemirror/addon/selection/active-line.js diff --git a/vendor/codemirror/keymap/emacs.js b/src/vendor/codemirror/keymap/emacs.js similarity index 100% rename from vendor/codemirror/keymap/emacs.js rename to src/vendor/codemirror/keymap/emacs.js diff --git a/vendor/codemirror/keymap/sublime.js b/src/vendor/codemirror/keymap/sublime.js similarity index 100% rename from vendor/codemirror/keymap/sublime.js rename to src/vendor/codemirror/keymap/sublime.js diff --git a/vendor/codemirror/keymap/vim.js b/src/vendor/codemirror/keymap/vim.js similarity index 100% rename from vendor/codemirror/keymap/vim.js rename to src/vendor/codemirror/keymap/vim.js diff --git a/vendor/codemirror/lib/codemirror.css b/src/vendor/codemirror/lib/codemirror.css similarity index 100% rename from vendor/codemirror/lib/codemirror.css rename to src/vendor/codemirror/lib/codemirror.css diff --git a/vendor/codemirror/lib/codemirror.js b/src/vendor/codemirror/lib/codemirror.js similarity index 100% rename from vendor/codemirror/lib/codemirror.js rename to src/vendor/codemirror/lib/codemirror.js diff --git a/vendor/codemirror/mode/css/css.js b/src/vendor/codemirror/mode/css/css.js similarity index 100% rename from vendor/codemirror/mode/css/css.js rename to src/vendor/codemirror/mode/css/css.js diff --git a/vendor/codemirror/mode/javascript/javascript.js b/src/vendor/codemirror/mode/javascript/javascript.js similarity index 100% rename from vendor/codemirror/mode/javascript/javascript.js rename to src/vendor/codemirror/mode/javascript/javascript.js diff --git a/vendor/codemirror/mode/stylus/stylus.js b/src/vendor/codemirror/mode/stylus/stylus.js similarity index 100% rename from vendor/codemirror/mode/stylus/stylus.js rename to src/vendor/codemirror/mode/stylus/stylus.js diff --git a/vendor/db-to-cloud/LICENSE b/src/vendor/db-to-cloud/LICENSE similarity index 100% rename from vendor/db-to-cloud/LICENSE rename to src/vendor/db-to-cloud/LICENSE diff --git a/vendor/db-to-cloud/README.md b/src/vendor/db-to-cloud/README.md similarity index 100% rename from vendor/db-to-cloud/README.md rename to src/vendor/db-to-cloud/README.md diff --git a/vendor/db-to-cloud/db-to-cloud.js b/src/vendor/db-to-cloud/db-to-cloud.js similarity index 100% rename from vendor/db-to-cloud/db-to-cloud.js rename to src/vendor/db-to-cloud/db-to-cloud.js diff --git a/vendor/draggable-list/LICENSE b/src/vendor/draggable-list/LICENSE similarity index 100% rename from vendor/draggable-list/LICENSE rename to src/vendor/draggable-list/LICENSE diff --git a/vendor/draggable-list/README.md b/src/vendor/draggable-list/README.md similarity index 100% rename from vendor/draggable-list/README.md rename to src/vendor/draggable-list/README.md diff --git a/vendor/draggable-list/draggable-list.iife.js b/src/vendor/draggable-list/draggable-list.iife.js similarity index 100% rename from vendor/draggable-list/draggable-list.iife.js rename to src/vendor/draggable-list/draggable-list.iife.js diff --git a/vendor/jsonlint/LICENSE b/src/vendor/jsonlint/LICENSE similarity index 100% rename from vendor/jsonlint/LICENSE rename to src/vendor/jsonlint/LICENSE diff --git a/vendor/jsonlint/README.md b/src/vendor/jsonlint/README.md similarity index 100% rename from vendor/jsonlint/README.md rename to src/vendor/jsonlint/README.md diff --git a/vendor/jsonlint/jsonlint.js b/src/vendor/jsonlint/jsonlint.js similarity index 100% rename from vendor/jsonlint/jsonlint.js rename to src/vendor/jsonlint/jsonlint.js diff --git a/vendor/less/LICENSE b/src/vendor/less/LICENSE similarity index 100% rename from vendor/less/LICENSE rename to src/vendor/less/LICENSE diff --git a/vendor/less/README.md b/src/vendor/less/README.md similarity index 100% rename from vendor/less/README.md rename to src/vendor/less/README.md diff --git a/vendor/less/less.min.js b/src/vendor/less/less.min.js similarity index 100% rename from vendor/less/less.min.js rename to src/vendor/less/less.min.js diff --git a/vendor/lz-string-unsafe/LICENSE b/src/vendor/lz-string-unsafe/LICENSE similarity index 100% rename from vendor/lz-string-unsafe/LICENSE rename to src/vendor/lz-string-unsafe/LICENSE diff --git a/vendor/lz-string-unsafe/README.md b/src/vendor/lz-string-unsafe/README.md similarity index 100% rename from vendor/lz-string-unsafe/README.md rename to src/vendor/lz-string-unsafe/README.md diff --git a/vendor/lz-string-unsafe/lz-string-unsafe.min.js b/src/vendor/lz-string-unsafe/lz-string-unsafe.min.js similarity index 100% rename from vendor/lz-string-unsafe/lz-string-unsafe.min.js rename to src/vendor/lz-string-unsafe/lz-string-unsafe.min.js diff --git a/vendor/stylelint-bundle/LICENSE b/src/vendor/stylelint-bundle/LICENSE similarity index 100% rename from vendor/stylelint-bundle/LICENSE rename to src/vendor/stylelint-bundle/LICENSE diff --git a/vendor/stylelint-bundle/README.md b/src/vendor/stylelint-bundle/README.md similarity index 100% rename from vendor/stylelint-bundle/README.md rename to src/vendor/stylelint-bundle/README.md diff --git a/vendor/stylelint-bundle/stylelint-bundle.min.js b/src/vendor/stylelint-bundle/stylelint-bundle.min.js similarity index 100% rename from vendor/stylelint-bundle/stylelint-bundle.min.js rename to src/vendor/stylelint-bundle/stylelint-bundle.min.js diff --git a/vendor/stylus-lang-bundle/LICENSE b/src/vendor/stylus-lang-bundle/LICENSE similarity index 100% rename from vendor/stylus-lang-bundle/LICENSE rename to src/vendor/stylus-lang-bundle/LICENSE diff --git a/vendor/stylus-lang-bundle/README.md b/src/vendor/stylus-lang-bundle/README.md similarity index 100% rename from vendor/stylus-lang-bundle/README.md rename to src/vendor/stylus-lang-bundle/README.md diff --git a/vendor/stylus-lang-bundle/stylus-renderer.min.js b/src/vendor/stylus-lang-bundle/stylus-renderer.min.js similarity index 100% rename from vendor/stylus-lang-bundle/stylus-renderer.min.js rename to src/vendor/stylus-lang-bundle/stylus-renderer.min.js diff --git a/vendor/usercss-meta/LICENSE b/src/vendor/usercss-meta/LICENSE similarity index 100% rename from vendor/usercss-meta/LICENSE rename to src/vendor/usercss-meta/LICENSE diff --git a/vendor/usercss-meta/README.md b/src/vendor/usercss-meta/README.md similarity index 100% rename from vendor/usercss-meta/README.md rename to src/vendor/usercss-meta/README.md diff --git a/vendor/usercss-meta/usercss-meta.js b/src/vendor/usercss-meta/usercss-meta.js similarity index 100% rename from vendor/usercss-meta/usercss-meta.js rename to src/vendor/usercss-meta/usercss-meta.js diff --git a/vendor/webext-launch-web-auth-flow/LICENSE b/src/vendor/webext-launch-web-auth-flow/LICENSE similarity index 100% rename from vendor/webext-launch-web-auth-flow/LICENSE rename to src/vendor/webext-launch-web-auth-flow/LICENSE diff --git a/vendor/webext-launch-web-auth-flow/README.md b/src/vendor/webext-launch-web-auth-flow/README.md similarity index 100% rename from vendor/webext-launch-web-auth-flow/README.md rename to src/vendor/webext-launch-web-auth-flow/README.md diff --git a/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js b/src/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js similarity index 100% rename from vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js rename to src/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js From 7fa95a1fc141b4fce71aca214f5b117f1cc6d7ef Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 29 Sep 2024 15:27:53 +0300 Subject: [PATCH 002/148] WIP --- .eslintignore | 1 + .eslintrc.yml | 42 +- jsconfig.json | 2 +- package-lock.json | 11269 +++++++++++----- package.json | 20 +- rollup.config.mjs | 116 + src/background.html | 1 + src/background/background-worker.js | 9 +- src/background/bg-prefs.js | 72 +- src/background/broadcast-injector-config.js | 36 + src/background/broadcast.js | 35 + src/background/browser-cmd-hotkeys.js | 26 +- src/background/color-scheme.js | 187 +- src/background/common.js | 287 +- src/background/content-scripts.js | 16 +- src/background/context-menus.js | 21 +- src/background/db-chrome-storage.js | 6 +- src/background/db.js | 254 +- src/background/download.js | 131 + src/background/icon-manager.js | 447 +- src/background/{background.js => index.js} | 66 +- src/background/navigation-manager.js | 90 +- src/background/style-cache.js | 60 + src/background/style-manager.js | 1577 ++- src/background/style-search-db.js | 180 +- src/background/style-via-api.js | 16 +- src/background/style-via-webrequest.js | 331 +- src/background/sync-manager.js | 540 +- src/background/tab-manager.js | 122 +- src/background/tab-util.js | 19 +- src/background/token-manager.js | 478 +- src/background/update-manager.js | 547 +- src/background/usercss-install-helper.js | 215 +- src/background/usercss-manager.js | 273 +- src/background/uso-api.js | 209 +- src/background/usw-api.js | 223 +- src/content/apply.js | 514 +- src/content/install-hook-greasyfork.js | 2 +- src/content/install-hook-usercss.js | 2 +- src/content/install-hook-userstyles.js | 4 +- src/content/install-hook-userstylesworld.js | 2 +- src/content/style-injector.js | 15 +- src/edit.html | 80 +- src/edit/autocomplete.js | 20 +- src/edit/base.js | 433 - src/edit/beautify.js | 22 +- src/edit/codemirror-default.js | 53 +- src/edit/codemirror-factory.js | 602 +- src/edit/codemirror-themes.js | 137 +- src/edit/compact-header.js | 47 + src/edit/drafts.js | 45 +- src/edit/edit.js | 412 - src/edit/editor-worker.js | 313 +- src/edit/editor.js | 16 +- src/edit/embedded-popup.js | 15 +- src/edit/global-search.js | 70 +- src/edit/index.js | 61 +- src/edit/linter-dialogs.js | 464 +- src/edit/linter-manager.js | 16 +- src/edit/live-preview.js | 3 +- src/edit/moz-section-finder.js | 10 +- src/edit/moz-section-widget.js | 25 +- src/edit/regexp-tester.js | 379 +- src/edit/sections-editor-section.js | 26 +- src/edit/sections-editor.js | 40 +- src/edit/settings.js | 32 +- src/edit/show-keymap-help.js | 19 +- src/edit/source-editor.js | 43 +- src/edit/usw-integration.js | 18 +- src/edit/util.js | 54 +- src/edit/windowed-mode.js | 6 +- src/injection-order/injection-order.js | 17 +- src/install-usercss/install-usercss.js | 27 +- src/install-usercss/preinit.js | 8 +- src/js/browser.js | 12 +- src/js/cmpver.js | 6 +- src/js/color/color-converter.js | 481 +- src/js/color/color-mimicry.js | 80 +- src/js/color/color-picker.js | 30 +- src/js/color/color-view.js | 1292 +- src/js/csslint/csslint.js | 4 +- src/js/csslint/parserlib.js | 4 +- src/js/dlg/config-dialog.js | 40 +- src/js/dlg/message-box.js | 15 +- src/js/dom-base.js | 12 - src/js/dom-on-load.js | 24 +- src/js/dom-util.js | 1 + src/js/dom.js | 436 +- src/js/header-resizer.js | 9 +- src/js/jsonlint-bundle.js | 3 + src/js/localization.js | 18 +- src/js/meta-parser.js | 7 +- src/js/moz-parser.js | 6 +- src/js/msg-base.js | 158 + src/js/msg.js | 215 +- src/js/popup-get-styles.js | 14 +- src/js/prefs.js | 469 +- src/js/router.js | 10 +- src/js/sections-util.js | 26 +- src/js/storage-util.js | 84 +- src/js/themer.js | 12 +- src/js/toolbox.js | 148 +- src/js/usercss-compiler.js | 12 +- src/js/worker-host.js | 43 + src/js/worker-util.js | 79 +- src/manage/events.js | 22 +- src/manage/filters.js | 28 +- src/manage/import-export.js | 38 +- src/manage/incremental-search.js | 14 +- src/manage/manage.js | 32 +- src/manage/render.js | 14 +- src/manage/sorter.js | 14 +- src/manage/updater-ui.js | 18 +- src/manifest.json | 35 +- src/options/options-sync.js | 11 +- src/options/options.js | 15 +- src/popup/events.js | 15 +- src/popup/hotkeys.js | 9 +- src/popup/popup.js | 46 +- src/popup/search.js | 16 +- .../codemirror-addon/match-highlighter.js | 13 +- src/vendor/codemirror/LICENSE | 21 - src/vendor/codemirror/README.md | 35 - .../codemirror/addon/comment/comment.js | 211 - src/vendor/codemirror/addon/dialog/dialog.css | 32 - src/vendor/codemirror/addon/dialog/dialog.js | 163 - .../codemirror/addon/edit/closebrackets.js | 201 - .../codemirror/addon/edit/matchbrackets.js | 160 - .../codemirror/addon/fold/brace-fold.js | 119 - .../codemirror/addon/fold/comment-fold.js | 59 - src/vendor/codemirror/addon/fold/foldcode.js | 159 - .../codemirror/addon/fold/foldgutter.css | 20 - .../codemirror/addon/fold/foldgutter.js | 169 - .../codemirror/addon/fold/indent-fold.js | 48 - .../codemirror/addon/hint/anyword-hint.js | 41 - src/vendor/codemirror/addon/hint/css-hint.js | 66 - .../codemirror/addon/hint/show-hint.css | 37 - src/vendor/codemirror/addon/hint/show-hint.js | 523 - src/vendor/codemirror/addon/lint/css-lint.js | 40 - src/vendor/codemirror/addon/lint/json-lint.js | 40 - src/vendor/codemirror/addon/lint/lint.css | 79 - src/vendor/codemirror/addon/lint/lint.js | 291 - .../addon/scroll/annotatescrollbar.js | 128 - .../addon/search/matchesonscrollbar.css | 8 - .../addon/search/matchesonscrollbar.js | 97 - .../codemirror/addon/search/searchcursor.js | 305 - .../codemirror/addon/selection/active-line.js | 72 - src/vendor/codemirror/keymap/emacs.js | 545 - src/vendor/codemirror/keymap/sublime.js | 720 - src/vendor/codemirror/keymap/vim.js | 5978 -------- src/vendor/codemirror/lib/codemirror.css | 344 - src/vendor/codemirror/lib/codemirror.js | 9872 -------------- src/vendor/codemirror/mode/css/css.js | 862 -- .../codemirror/mode/javascript/javascript.js | 960 -- src/vendor/codemirror/mode/stylus/stylus.js | 775 -- src/vendor/jsonlint/jsonlint.js | 23 +- src/vendor/lz-string-unsafe/LICENSE | 13 - src/vendor/lz-string-unsafe/README.md | 4 - .../lz-string-unsafe/lz-string-unsafe.min.js | 1 - src/vendor/stylus-lang-bundle/README.md | 2 +- .../stylus-lang-bundle/stylus-renderer.min.js | 17 +- tools/build-vendor.js | 67 +- tools/chrome-api-no-cb.js | 2 +- tools/shim/empty.js | 3 + tools/shim/path.js | 6 + 165 files changed, 14594 insertions(+), 34790 deletions(-) create mode 100644 rollup.config.mjs create mode 100644 src/background.html create mode 100644 src/background/broadcast-injector-config.js create mode 100644 src/background/broadcast.js create mode 100644 src/background/download.js rename src/background/{background.js => index.js} (64%) create mode 100644 src/background/style-cache.js delete mode 100644 src/edit/base.js create mode 100644 src/edit/compact-header.js delete mode 100644 src/edit/edit.js create mode 100644 src/js/jsonlint-bundle.js create mode 100644 src/js/msg-base.js create mode 100644 src/js/worker-host.js delete mode 100644 src/vendor/codemirror/LICENSE delete mode 100644 src/vendor/codemirror/README.md delete mode 100644 src/vendor/codemirror/addon/comment/comment.js delete mode 100644 src/vendor/codemirror/addon/dialog/dialog.css delete mode 100644 src/vendor/codemirror/addon/dialog/dialog.js delete mode 100644 src/vendor/codemirror/addon/edit/closebrackets.js delete mode 100644 src/vendor/codemirror/addon/edit/matchbrackets.js delete mode 100644 src/vendor/codemirror/addon/fold/brace-fold.js delete mode 100644 src/vendor/codemirror/addon/fold/comment-fold.js delete mode 100644 src/vendor/codemirror/addon/fold/foldcode.js delete mode 100644 src/vendor/codemirror/addon/fold/foldgutter.css delete mode 100644 src/vendor/codemirror/addon/fold/foldgutter.js delete mode 100644 src/vendor/codemirror/addon/fold/indent-fold.js delete mode 100644 src/vendor/codemirror/addon/hint/anyword-hint.js delete mode 100644 src/vendor/codemirror/addon/hint/css-hint.js delete mode 100644 src/vendor/codemirror/addon/hint/show-hint.css delete mode 100644 src/vendor/codemirror/addon/hint/show-hint.js delete mode 100644 src/vendor/codemirror/addon/lint/css-lint.js delete mode 100644 src/vendor/codemirror/addon/lint/json-lint.js delete mode 100644 src/vendor/codemirror/addon/lint/lint.css delete mode 100644 src/vendor/codemirror/addon/lint/lint.js delete mode 100644 src/vendor/codemirror/addon/scroll/annotatescrollbar.js delete mode 100644 src/vendor/codemirror/addon/search/matchesonscrollbar.css delete mode 100644 src/vendor/codemirror/addon/search/matchesonscrollbar.js delete mode 100644 src/vendor/codemirror/addon/search/searchcursor.js delete mode 100644 src/vendor/codemirror/addon/selection/active-line.js delete mode 100644 src/vendor/codemirror/keymap/emacs.js delete mode 100644 src/vendor/codemirror/keymap/sublime.js delete mode 100644 src/vendor/codemirror/keymap/vim.js delete mode 100644 src/vendor/codemirror/lib/codemirror.css delete mode 100644 src/vendor/codemirror/lib/codemirror.js delete mode 100644 src/vendor/codemirror/mode/css/css.js delete mode 100644 src/vendor/codemirror/mode/javascript/javascript.js delete mode 100644 src/vendor/codemirror/mode/stylus/stylus.js delete mode 100644 src/vendor/lz-string-unsafe/LICENSE delete mode 100644 src/vendor/lz-string-unsafe/README.md delete mode 100644 src/vendor/lz-string-unsafe/lz-string-unsafe.min.js create mode 100644 tools/shim/empty.js create mode 100644 tools/shim/path.js diff --git a/.eslintignore b/.eslintignore index a710e41305b..62a10be96a3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ +dist/ vendor/ vendor-overwrites/ diff --git a/.eslintrc.yml b/.eslintrc.yml index 72c84e05e70..2a0636f07cd 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,15 +1,16 @@ # https://github.com/eslint/eslint/blob/master/docs/rules/README.md parserOptions: - ecmaVersion: 2017 + ecmaVersion: 2023 + sourceType: module env: browser: true es6: true - webextensions: true globals: - require: readonly # in toolbox.js + __BUILD: false + __ENTRY: false rules: accessor-pairs: [2] @@ -22,7 +23,13 @@ rules: brace-style: [2, 1tbs, {allowSingleLine: true}] camelcase: [2, {properties: never}] class-methods-use-this: [2] - comma-dangle: [2, {arrays: always-multiline, objects: always-multiline}] + comma-dangle: [2, { + arrays: always-multiline, + objects: always-multiline, + exports: always-multiline, + imports: always-multiline, + functions: only-multiline + }] comma-spacing: [2, {before: false, after: true}] comma-style: [2, last] complexity: [0] @@ -59,7 +66,7 @@ rules: keyword-spacing: [2] lines-around-comment: [0] lines-around-directive: [0] - max-len: [2, {code: 120, ignoreComments: true, ignoreRegExpLiterals: true}] + max-len: [2, {code: 100, ignoreComments: true, ignoreRegExpLiterals: true}] max-lines: [0] max-nested-callbacks: [0] max-params: [0] @@ -230,24 +237,31 @@ rules: yoda: [2, never] overrides: - - files: [tools/*] + - files: [tools/**/*] env: node: true browser: false webextensions: false parserOptions: ecmaVersion: 2021 + sourceType: script - - files: ["**/*worker*.js"] + - files: + - "**/*-worker.js" + - src/js/meta-parser.js + - src/js/moz-parser.js + - src/js/usercss-compiler.js + - src/js/worker-util.js env: worker: true + parserOptions: + sourceType: script + globals: + createWorkerApi: false - - files: [background/*] + - files: + src/content/* rules: - no-restricted-syntax: [2, { - selector: 'MemberExpression[object.name="API"][property.name="styles"]', - message: 'Please use `styleMan` as some of its methods exposed on `API` are synchronous in bg context' - }, { - selector: 'MemberExpression[object.object.name="API"][object.property.name="usercss"][property.name="find"]', - message: 'Please use `usercssMan` for synchronous methods in bg context' + no-restricted-imports: [2, { + paths: [{name: "/js/msg", message: "Use 'msg-base' in content scripts."}] }] diff --git a/jsconfig.json b/jsconfig.json index 87c0cea9f71..2d5880efc9e 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "/*": ["./*"] + "/*": ["./src/*"] } }, "exclude": ["node_modules"], diff --git a/package-lock.json b/package-lock.json index 819812115c0..a2263585e66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,8 +21,12 @@ "webext-launch-web-auth-flow": "^0.1.1" }, "devDependencies": { - "@types/chrome": "^0.0.263", - "@types/firefox-webext-browser": "^120.0.3", + "@babel/preset-env": "^7.25.4", + "@rollup/plugin-alias": "^5.1.1", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^28.0.0", + "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-terser": "^0.4.4", "chalk": "^4.1.2", "eslint": "^8.48.0", "fast-glob": "^3.3.1", @@ -31,6 +35,9 @@ "node-fetch": "^2.7.0", "postcss": "^8.4.32", "postcss-preset-env": "^9.3.0", + "rollup": "^4.22.5", + "rollup-plugin-copy": "^3.5.0", + "rollup-plugin-css-only": "^4.5.2", "svg2ttf": "^6.0.3", "svgicons2svgfont": "^12.0.0", "sync-version": "^1.0.1" @@ -53,32 +60,367 @@ "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==" }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "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==", "dependencies": { - "@babel/highlight": "^7.24.2", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -151,1406 +493,1329 @@ "node": ">=4" } }, - "node_modules/@csstools/cascade-layer-name-parser": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.6.tgz", - "integrity": "sha512-HkxRNs6ZIV0VjLFw6k5G8K35vd9r+O8B1Vr+QVD8M5Y44eQxyHtc42BdF74FQatXACPnitOR1+sRx2oWdnKTQw==", + "node_modules/@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/types": "^7.25.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/color-helpers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-4.0.0.tgz", - "integrity": "sha512-wjyXB22/h2OvxAr3jldPB7R7kjTUEzopvjitS8jWtyd8fN6xJ8vy1HnHu0ZNfEkqpBJgQ76Q+sBDshWcMvTa/w==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/css-calc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-1.1.5.tgz", - "integrity": "sha512-UhI5oSRAUtTHY3MyGahqn0ZzQOHVoPpfvUcOmYipAZ1rILAvCBoyiLSsa/clv1Xxct0SMKIq93KO5Bfl1cb6tQ==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/css-color-parser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-1.5.0.tgz", - "integrity": "sha512-PUhSg1MgU2sjYhA6moOmxYesqVqYTJwcVw12boTNbDX7Af+VK02MkgvmBBY2Z2qU6UN5HOQ+wrF0qQJGsTFY7w==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/color-helpers": "^4.0.0", - "@csstools/css-calc": "^1.1.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/core": "^7.13.0" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.3.tgz", - "integrity": "sha512-xI/tL2zxzEbESvnSxwFgwvy5HS00oCXxL4MLs6HUiDcYfwowsoQaABKxUElp1ARITrINzBnsECOc1q0eg2GOrA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.3.1" + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/css-tokenizer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.3.1.tgz", - "integrity": "sha512-iMNHTyxLbBlWIfGtabT157LH9DUx9X8+Y3oymFEuMj8HNc+rpE3dPFGFgHjpKfjeFDjLjYIAIhXPGvS2lKxL9g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.11.tgz", - "integrity": "sha512-uox5MVhvNHqitPP+SynrB1o8oPxPMt2JLgp5ghJOWf54WGQ5OKu47efne49r1SWqs3wRP8xSWjnO9MBKxhB1dA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "engines": { - "node": "^14 || ^16 || >=18" + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.6.3", - "@csstools/css-tokenizer": "^2.3.1" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-cascade-layers": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-4.0.2.tgz", - "integrity": "sha512-PqM+jvg5T2tB4FHX+akrMGNWAygLupD4FNUjcv4PSvtVuWZ6ISxuo37m4jFGU7Jg3rCfloGzKd0+xfr5Ec3vZQ==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/selector-specificity": "^3.0.1", - "postcss-selector-parser": "^6.0.13" - }, - "engines": { - "node": "^14 || ^16 || >=18" + "@babel/helper-plugin-utils": "^7.12.13" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-color-function": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-3.0.8.tgz", - "integrity": "sha512-jvbF7eCRbIcxWqby0kk2Mt85QtGzRRpFFYdlJCJ80Tuiv43PY+auS/nBl8pDQQ4Ndm4vsm4IC/wCZDcJUmpJmg==", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-color-mix-function": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-2.0.8.tgz", - "integrity": "sha512-sGhk+TdZ2TeXspc6LSYSYC8WgzLlxoknUaObKgB0mk+dNjRQgSSIeCU+qrCwvHmwM+uTNKtiS8mntDzyQLHTTA==", + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" - }, - "engines": { - "node": "^14 || ^16 || >=18" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-exponential-functions": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-1.0.2.tgz", - "integrity": "sha512-VRIYrwNCkZRqzsGB4jGT+XcNXsoiwyqy0Vf7C3I/5OPcf7WcWK3G1sBYFqqgWLGtpwc7m1m8TcorGY1xdh5abg==", + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-calc": "^1.1.5", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" - }, - "engines": { - "node": "^14 || ^16 || >=18" + "@babel/helper-plugin-utils": "^7.8.3" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-font-format-keywords": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-3.0.1.tgz", - "integrity": "sha512-D1lcG2sfotTq6yBEOMV3myFxJLT10F3DLYZJMbiny5YToqzHWodZen8WId3UTimm0mEHitXqAUNL5jdd6RzVdA==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-value-parser": "^4.2.0" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-gamut-mapping": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-1.0.1.tgz", - "integrity": "sha512-GDVzfNbnc7x3GusFklvt0mYXIWVzxEtEtTFEW664NgZh/5V7Z89hZKBMl9piOAHXuxijfHtE+kul/ShfeLUvcA==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-gradients-interpolation-method": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-4.0.8.tgz", - "integrity": "sha512-bmvCNzuUvWPPdgASh0T14ffTay/FdzXsXfp0wXT1pYoUPmkH9M6yyxwPEkHq5djjzSb2jiLl4Ta3XM1uOREQ2w==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" - }, - "engines": { - "node": "^14 || ^16 || >=18" + "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-hwb-function": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-3.0.7.tgz", - "integrity": "sha512-iXs1gxKtev8YNP5bOF26TAsnMfcxnCRLpKItQ067RphYECKEK/xWm4Z0r4ChmV1U1eq+lbdH5ZIb2cju4o5akA==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": "^14 || ^16 || >=18" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-ic-unit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-3.0.3.tgz", - "integrity": "sha512-MpcmIL0/uMm/cFWh5V/9nbKKJ7jRr2qTYW5Q6zoE6HZ6uzOBJr2KRERv5/x8xzEBQ1MthDT7iP1EBp9luSQy7g==", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^3.0.3", - "postcss-value-parser": "^4.2.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": "^14 || ^16 || >=18" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-initial": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-1.0.1.tgz", - "integrity": "sha512-wtb+IbUIrIf8CrN6MLQuFR7nlU5C7PwuebfeEXfjthUha1+XZj2RVi+5k/lukToA24sZkYAiSJfHM8uG/UZIdg==", + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "engines": { - "node": "^14 || ^16 || >=18" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-4.0.4.tgz", - "integrity": "sha512-vTVO/uZixpTVAOQt3qZRUFJ/K1L03OfNkeJ8sFNDVNdVy/zW0h1L5WT7HIPMDUkvSrxQkFaCCybTZkUP7UESlQ==", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/selector-specificity": "^3.0.1", - "postcss-selector-parser": "^6.0.13" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": "^14 || ^16 || >=18" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-logical-float-and-clear": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-2.0.1.tgz", - "integrity": "sha512-SsrWUNaXKr+e/Uo4R/uIsqJYt3DaggIh/jyZdhy/q8fECoJSKsSMr7nObSLdvoULB69Zb6Bs+sefEIoMG/YfOA==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-logical-overflow": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-1.0.1.tgz", - "integrity": "sha512-Kl4lAbMg0iyztEzDhZuQw8Sj9r2uqFDcU1IPl+AAt2nue8K/f1i7ElvKtXkjhIAmKiy5h2EY8Gt/Cqg0pYFDCw==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-logical-overscroll-behavior": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-1.0.1.tgz", - "integrity": "sha512-+kHamNxAnX8ojPCtV8WPcUP3XcqMFBSDuBuvT6MHgq7oX4IQxLIXKx64t7g9LiuJzE7vd06Q9qUYR6bh4YnGpQ==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/postcss-logical-resize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-2.0.1.tgz", - "integrity": "sha512-W5Gtwz7oIuFcKa5SmBjQ2uxr8ZoL7M2bkoIf0T1WeNqljMkBrfw1DDA8/J83k57NQ1kcweJEjkJ04pUkmyee3A==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-value-parser": "^4.2.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-logical-viewport-units": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-2.0.4.tgz", - "integrity": "sha512-jetp/ArGAniWbjWBh5UQ07ztawfSbqCFd0QelX4R4pVIxrXahUEhz5VZHebMPVCg02J8GsQn0br6fdRpY6t7lw==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-tokenizer": "^2.2.2" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-media-minmax": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.1.1.tgz", - "integrity": "sha512-mBY46/Hr+A8cDjoX0OoPRBOVrkANym9540dSB9rN3dllPZdM1E112i/tVxWsrR1s1yE9gfF0pk+7lf9l+qSeHA==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-calc": "^1.1.5", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/media-query-list-parser": "^2.1.6" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.4.tgz", - "integrity": "sha512-IaIZZhH0Qy9UDn7u+N3cuwwPG0Po3ZKOdDh+ClR7xvisSqniG+PuVrOEWYJrFKOt2//UHLhd7KHDqr2u9LKS9Q==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/media-query-list-parser": "^2.1.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-nested-calc": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-3.0.1.tgz", - "integrity": "sha512-bwwababZpWRm0ByHaWBxTsDGTMhZKmtUNl3Wt0Eom8AY7ORgXx5qF9SSk1vEFrCi+HOfJT6M6W5KPgzXuQNRwQ==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-value-parser": "^4.2.0" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-normalize-display-values": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-3.0.2.tgz", - "integrity": "sha512-fCapyyT/dUdyPtrelQSIV+d5HqtTgnNP/BEG9IuhgXHt93Wc4CfC1bQ55GzKAjWrZbgakMQ7MLfCXEf3rlZJOw==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-value-parser": "^4.2.0" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-oklab-function": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-3.0.8.tgz", - "integrity": "sha512-L4xrwbgg+k08v+a88LDxJeIM6+kqaBJlYb/QgmEMfQpUbrfXTp87DuRc7utcRdDvY+qWK5vqz3h1xUtceB5LJQ==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.12.0" } }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-3.0.3.tgz", - "integrity": "sha512-WipTVh6JTMQfeIrzDV4wEPsV9NTzMK2jwXxyH6CGBktuWdivHnkioP/smp1x/0QDPQyx7NTS14RB+GV3zZZYEw==", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-value-parser": "^4.2.0" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-relative-color-syntax": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-2.0.8.tgz", - "integrity": "sha512-wu/Oh7QKINpRXnmLMUbObVNlqwr843PSF4a3x3fMC0I+vUeoGqMfZuSPFtT+NnYYxfzUjEZ091GURPxee22VLQ==", + "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.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-scope-pseudo-class": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-3.0.1.tgz", - "integrity": "sha512-3ZFonK2gfgqg29gUJ2w7xVw2wFJ1eNWVDONjbzGkm73gJHVCYK5fnCqlLr+N+KbEfv2XbWAO0AaOJCFB6Fer6A==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-selector-parser": "^6.0.13" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-3.0.3.tgz", - "integrity": "sha512-hzo9Wr3u7JJiM65/EyHgE/gJpBzhDwBSGOobFs2YQ0ZNTywUliYQoYJud1KKlByMRuhqvDLh9V95eIkLf/fZTQ==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-calc": "^1.1.5", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-3.0.4.tgz", - "integrity": "sha512-yUZmbnUemgQmja7SpOZeU45+P49wNEgQguRdyTktFkZsHf7Gof+ZIYfvF6Cm+LsU1PwSupy4yUeEKKjX5+k6cQ==", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/color-helpers": "^4.0.0", - "postcss-value-parser": "^4.2.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-3.0.3.tgz", - "integrity": "sha512-T/npTbDuMZ3vktEMuA05p1oeVd12Sy47qZP1vFhzNMUOdXGCK9vlm0tUSIlV5DdlbTJqKqq9FhGitZH9VTKrfQ==", + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-calc": "^1.1.5", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/postcss-unset-value": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-3.0.1.tgz", - "integrity": "sha512-dbDnZ2ja2U8mbPP0Hvmt2RMEGBiF1H7oY6HYSpjteXJGihYwgxgTr6KRbbJ/V6c+4wd51M+9980qG4gKVn5ttg==", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/selector-specificity": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", - "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss-selector-parser": "^6.0.13" - } - }, - "node_modules/@dual-bundle/import-meta-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eight04/draggable-list": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eight04/draggable-list/-/draggable-list-0.3.0.tgz", - "integrity": "sha512-3mDCUv/dCIylc7BA8VZVW8kB0Y937UqVOgORN9vyCpgmzLTfO+0Qp00vRPaXJI7MBy+Ufg7c0K08y8/a41S3cw==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eight04/read-write-lock": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eight04/read-write-lock/-/read-write-lock-0.1.0.tgz", - "integrity": "sha512-a/94gK+/GRZeTyFmJCIPlWGlgpOT3qmIRp5ByJkoxtkpspSsMbdYZKd/wNXdPYf4auRyepEM3+EkawQnscjJXQ==" - }, - "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==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", - "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.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" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { - "node": ">=10.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, "engines": { - "node": ">=12.22" + "node": ">=6.9.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "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==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/chrome": { - "version": "0.0.263", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.263.tgz", - "integrity": "sha512-As0vzv99ov3M6ZR7R6VzhMWFZXkPMrFrCEXXVrMN576Cm70fTkj7Df2CF+qEo170JepX50pd11cX6O4DSAtl2Q==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", "dev": true, "dependencies": { - "@types/filesystem": "*", - "@types/har-format": "*" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/filesystem": { - "version": "0.0.36", - "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", - "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", "dev": true, "dependencies": { - "@types/filewriter": "*" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@types/filewriter": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", - "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", - "dev": true - }, - "node_modules/@types/firefox-webext-browser": { - "version": "120.0.3", - "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-120.0.3.tgz", - "integrity": "sha512-APbBSxOvFMbKwXy/4YrEVa5Di6N0C9yl4w0WA0xzdkOrChAfPQ/KlcC8QLyhemHCHpF1CB/zHy52+oUQurViOg==", - "dev": true - }, - "node_modules/@types/har-format": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.15.tgz", - "integrity": "sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==", - "dev": true - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@xmldom/xmldom": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", - "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, "engines": { - "node": ">=10.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { - "node": ">=0.4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "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==", "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/autoprefixer": { - "version": "10.4.16", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", - "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "dependencies": { - "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001538", - "fraction.js": "^4.3.6", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.1.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, "dependencies": { - "fill-range": "^7.1.1" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001570", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", - "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/codemirror": { - "version": "5.65.10", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.10.tgz", - "integrity": "sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==" - }, - "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==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==" + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/commander": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", - "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, "engines": { - "node": "^12.20.0 || >=14" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, "dependencies": { - "is-what": "^3.14.1" + "@babel/helper-plugin-utils": "^7.24.7" }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": ">=14" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "typescript": ">=4.9.5" + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/css-blank-pseudo": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-6.0.1.tgz", - "integrity": "sha512-goSnEITByxTzU4Oh5oJZrEWudxTqk7L6IXj1UW69pO6Hv0UdX+Vsrt02FFu5DweRh2bLu6WpX/+zsQCu5O1gKw==", + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "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.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.6.tgz", + "integrity": "sha512-HkxRNs6ZIV0VjLFw6k5G8K35vd9r+O8B1Vr+QVD8M5Y44eQxyHtc42BdF74FQatXACPnitOR1+sRx2oWdnKTQw==", "dev": true, "funding": [ { @@ -1562,28 +1827,18 @@ "url": "https://opencollective.com/csstools" } ], - "dependencies": { - "postcss-selector-parser": "^6.0.13" - }, "engines": { "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/css-functions-list": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", - "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", - "engines": { - "node": ">=12 || >=16" + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" } }, - "node_modules/css-has-pseudo": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-6.0.1.tgz", - "integrity": "sha512-WwoVKqNxApfEI7dWFyaHoeFCcUPD+lPyjL6lNpRUNX7IyIUuVpawOTwwA5D0ZR6V2xQZonNPVj8kEcxzEaAQfQ==", + "node_modules/@csstools/color-helpers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-4.0.0.tgz", + "integrity": "sha512-wjyXB22/h2OvxAr3jldPB7R7kjTUEzopvjitS8jWtyd8fN6xJ8vy1HnHu0ZNfEkqpBJgQ76Q+sBDshWcMvTa/w==", "dev": true, "funding": [ { @@ -1595,22 +1850,14 @@ "url": "https://opencollective.com/csstools" } ], - "dependencies": { - "@csstools/selector-specificity": "^3.0.1", - "postcss-selector-parser": "^6.0.13", - "postcss-value-parser": "^4.2.0" - }, "engines": { "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" } }, - "node_modules/css-prefers-color-scheme": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-9.0.1.tgz", - "integrity": "sha512-iFit06ochwCKPRiWagbTa1OAWCvWWVdEnIFd8BaRrgO8YrrNh4RAWUQTFcYX5tdFZgFl1DJ3iiULchZyEbnF4g==", + "node_modules/@csstools/css-calc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-1.1.5.tgz", + "integrity": "sha512-UhI5oSRAUtTHY3MyGahqn0ZzQOHVoPpfvUcOmYipAZ1rILAvCBoyiLSsa/clv1Xxct0SMKIq93KO5Bfl1cb6tQ==", "dev": true, "funding": [ { @@ -1626,1341 +1873,1572 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "postcss": "^8.4" + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "node_modules/@csstools/css-color-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-1.5.0.tgz", + "integrity": "sha512-PUhSg1MgU2sjYhA6moOmxYesqVqYTJwcVw12boTNbDX7Af+VK02MkgvmBBY2Z2qU6UN5HOQ+wrF0qQJGsTFY7w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" + "@csstools/color-helpers": "^4.0.0", + "@csstools/css-calc": "^1.1.5" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" } }, - "node_modules/cssdb": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.9.1.tgz", - "integrity": "sha512-fqy6ZnNfpb8qAvTT0qijWyTsUmYThsDX2F2ctMG4ceI7mI4DtsMILSiMBiuuDnVIYTyWvCctdp9Nb08p/6m2SQ==", - "dev": true, + "node_modules/@csstools/css-parser-algorithms": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.3.tgz", + "integrity": "sha512-xI/tL2zxzEbESvnSxwFgwvy5HS00oCXxL4MLs6HUiDcYfwowsoQaABKxUElp1ARITrINzBnsECOc1q0eg2GOrA==", "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, { "type": "github", "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" } - ] - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, + ], "engines": { - "node": ">=4" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^2.3.1" } }, - "node_modules/cubic2quad": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cubic2quad/-/cubic2quad-1.2.1.tgz", - "integrity": "sha512-wT5Y7mO8abrV16gnssKdmIhIbA9wSkeMzhh27jAguKrV82i24wER0vL5TGhUJ9dbJNDcigoRZ0IAHFEEEI4THQ==", - "dev": true - }, - "node_modules/db-to-cloud": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/db-to-cloud/-/db-to-cloud-0.7.0.tgz", - "integrity": "sha512-fs3FS6vMLk7E6gnuao9lJqTU+ohy6Pa9fqgZSVnoICMsCfqrnyYj+reA81xOmw9kfqVQNdtu+zZv67IJThrMvA==", - "dependencies": { - "@eight04/read-write-lock": "^0.1.0", - "universal-base64": "^2.1.0" - }, + "node_modules/@csstools/css-tokenizer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.3.1.tgz", + "integrity": "sha512-iMNHTyxLbBlWIfGtabT157LH9DUx9X8+Y3oymFEuMj8HNc+rpE3dPFGFgHjpKfjeFDjLjYIAIhXPGvS2lKxL9g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, + "node_modules/@csstools/media-query-list-parser": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.11.tgz", + "integrity": "sha512-uox5MVhvNHqitPP+SynrB1o8oPxPMt2JLgp5ghJOWf54WGQ5OKu47efne49r1SWqs3wRP8xSWjnO9MBKxhB1dA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=6.0" + "node": "^14 || ^16 || >=18" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.6.3", + "@csstools/css-tokenizer": "^2.3.1" } }, - "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/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/@csstools/postcss-cascade-layers": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-4.0.2.tgz", + "integrity": "sha512-PqM+jvg5T2tB4FHX+akrMGNWAygLupD4FNUjcv4PSvtVuWZ6ISxuo37m4jFGU7Jg3rCfloGzKd0+xfr5Ec3vZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "path-type": "^4.0.0" + "@csstools/selector-specificity": "^3.0.1", + "postcss-selector-parser": "^6.0.13" }, "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/docopt": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", - "integrity": "sha1-so6eIiDaXsSffqW7JKR3h0Be6xE=", - "dev": true - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/@csstools/postcss-color-function": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-3.0.8.tgz", + "integrity": "sha512-jvbF7eCRbIcxWqby0kk2Mt85QtGzRRpFFYdlJCJ80Tuiv43PY+auS/nBl8pDQQ4Ndm4vsm4IC/wCZDcJUmpJmg==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "esutils": "^2.0.2" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.615", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz", - "integrity": "sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" + }, "engines": { - "node": ">=6" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "optional": true, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-2.0.8.tgz", + "integrity": "sha512-sGhk+TdZ2TeXspc6LSYSYC8WgzLlxoknUaObKgB0mk+dNjRQgSSIeCU+qrCwvHmwM+uTNKtiS8mntDzyQLHTTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "prr": "~1.0.1" + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" }, - "bin": { - "errno": "cli.js" + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/@csstools/postcss-exponential-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-1.0.2.tgz", + "integrity": "sha512-VRIYrwNCkZRqzsGB4jGT+XcNXsoiwyqy0Vf7C3I/5OPcf7WcWK3G1sBYFqqgWLGtpwc7m1m8TcorGY1xdh5abg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "is-arrayish": "^0.2.1" + "@csstools/css-calc": "^1.1.5", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-3.0.1.tgz", + "integrity": "sha512-D1lcG2sfotTq6yBEOMV3myFxJLT10F3DLYZJMbiny5YToqzHWodZen8WId3UTimm0mEHitXqAUNL5jdd6RzVdA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">=6" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "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==", + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-1.0.1.tgz", + "integrity": "sha512-GDVzfNbnc7x3GusFklvt0mYXIWVzxEtEtTFEW664NgZh/5V7Z89hZKBMl9piOAHXuxijfHtE+kul/ShfeLUvcA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" + }, "engines": { - "node": ">=10" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-4.0.8.tgz", + "integrity": "sha512-bmvCNzuUvWPPdgASh0T14ffTay/FdzXsXfp0wXT1pYoUPmkH9M6yyxwPEkHq5djjzSb2jiLl4Ta3XM1uOREQ2w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "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" + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/@csstools/postcss-hwb-function": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-3.0.7.tgz", + "integrity": "sha512-iXs1gxKtev8YNP5bOF26TAsnMfcxnCRLpKItQ067RphYECKEK/xWm4Z0r4ChmV1U1eq+lbdH5ZIb2cju4o5akA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "postcss": "^8.4" } }, - "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==", + "node_modules/@csstools/postcss-ic-unit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-3.0.3.tgz", + "integrity": "sha512-MpcmIL0/uMm/cFWh5V/9nbKKJ7jRr2qTYW5Q6zoE6HZ6uzOBJr2KRERv5/x8xzEBQ1MthDT7iP1EBp9luSQy7g==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^3.0.3", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/@csstools/postcss-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-1.0.1.tgz", + "integrity": "sha512-wtb+IbUIrIf8CrN6MLQuFR7nlU5C7PwuebfeEXfjthUha1+XZj2RVi+5k/lukToA24sZkYAiSJfHM8uG/UZIdg==", "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-4.0.4.tgz", + "integrity": "sha512-vTVO/uZixpTVAOQt3qZRUFJ/K1L03OfNkeJ8sFNDVNdVy/zW0h1L5WT7HIPMDUkvSrxQkFaCCybTZkUP7UESlQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "estraverse": "^5.1.0" + "@csstools/selector-specificity": "^3.0.1", + "postcss-selector-parser": "^6.0.13" }, "engines": { - "node": ">=0.10" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-2.0.1.tgz", + "integrity": "sha512-SsrWUNaXKr+e/Uo4R/uIsqJYt3DaggIh/jyZdhy/q8fECoJSKsSMr7nObSLdvoULB69Zb6Bs+sefEIoMG/YfOA==", "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=4.0" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/@csstools/postcss-logical-overflow": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-1.0.1.tgz", + "integrity": "sha512-Kl4lAbMg0iyztEzDhZuQw8Sj9r2uqFDcU1IPl+AAt2nue8K/f1i7ElvKtXkjhIAmKiy5h2EY8Gt/Cqg0pYFDCw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "node_modules/event-lite": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.2.tgz", - "integrity": "sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "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==", - "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" + "node": "^14 || ^16 || >=18" }, - "engines": { - "node": ">=8.6.0" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "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", - "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", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-1.0.1.tgz", + "integrity": "sha512-+kHamNxAnX8ojPCtV8WPcUP3XcqMFBSDuBuvT6MHgq7oX4IQxLIXKx64t7g9LiuJzE7vd06Q9qUYR6bh4YnGpQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dependencies": { - "reusify": "^1.0.4" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/@csstools/postcss-logical-resize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-2.0.1.tgz", + "integrity": "sha512-W5Gtwz7oIuFcKa5SmBjQ2uxr8ZoL7M2bkoIf0T1WeNqljMkBrfw1DDA8/J83k57NQ1kcweJEjkJ04pUkmyee3A==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "flat-cache": "^3.0.4" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-2.0.4.tgz", + "integrity": "sha512-jetp/ArGAniWbjWBh5UQ07ztawfSbqCFd0QelX4R4pVIxrXahUEhz5VZHebMPVCg02J8GsQn0br6fdRpY6t7lw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "to-regex-range": "^5.0.1" + "@csstools/css-tokenizer": "^2.2.2" }, "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "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==", + "node_modules/@csstools/postcss-media-minmax": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.1.1.tgz", + "integrity": "sha512-mBY46/Hr+A8cDjoX0OoPRBOVrkANym9540dSB9rN3dllPZdM1E112i/tVxWsrR1s1yE9gfF0pk+7lf9l+qSeHA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "@csstools/css-calc": "^1.1.5", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/media-query-list-parser": "^2.1.6" }, "engines": { - "node": ">=10" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.4.tgz", + "integrity": "sha512-IaIZZhH0Qy9UDn7u+N3cuwwPG0Po3ZKOdDh+ClR7xvisSqniG+PuVrOEWYJrFKOt2//UHLhd7KHDqr2u9LKS9Q==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/media-query-list-parser": "^2.1.6" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "node_modules/@csstools/postcss-nested-calc": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-3.0.1.tgz", + "integrity": "sha512-bwwababZpWRm0ByHaWBxTsDGTMhZKmtUNl3Wt0Eom8AY7ORgXx5qF9SSk1vEFrCi+HOfJT6M6W5KPgzXuQNRwQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": "*" + "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-3.0.2.tgz", + "integrity": "sha512-fCapyyT/dUdyPtrelQSIV+d5HqtTgnNP/BEG9IuhgXHt93Wc4CfC1bQ55GzKAjWrZbgakMQ7MLfCXEf3rlZJOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=14.14" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/fs-extra/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "node_modules/@csstools/postcss-oklab-function": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-3.0.8.tgz", + "integrity": "sha512-L4xrwbgg+k08v+a88LDxJeIM6+kqaBJlYb/QgmEMfQpUbrfXTp87DuRc7utcRdDvY+qWK5vqz3h1xUtceB5LJQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" + }, "engines": { - "node": ">= 10.0.0" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-3.0.3.tgz", + "integrity": "sha512-WipTVh6JTMQfeIrzDV4wEPsV9NTzMK2jwXxyH6CGBktuWdivHnkioP/smp1x/0QDPQyx7NTS14RB+GV3zZZYEw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "*" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "postcss": "^8.4" } }, - "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==", + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-2.0.8.tgz", + "integrity": "sha512-wu/Oh7QKINpRXnmLMUbObVNlqwr843PSF4a3x3fMC0I+vUeoGqMfZuSPFtT+NnYYxfzUjEZ091GURPxee22VLQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "is-glob": "^4.0.3" + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" }, "engines": { - "node": ">=10.13.0" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-3.0.1.tgz", + "integrity": "sha512-3ZFonK2gfgqg29gUJ2w7xVw2wFJ1eNWVDONjbzGkm73gJHVCYK5fnCqlLr+N+KbEfv2XbWAO0AaOJCFB6Fer6A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "global-prefix": "^3.0.0" + "postcss-selector-parser": "^6.0.13" }, "engines": { - "node": ">=6" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-3.0.3.tgz", + "integrity": "sha512-hzo9Wr3u7JJiM65/EyHgE/gJpBzhDwBSGOobFs2YQ0ZNTywUliYQoYJud1KKlByMRuhqvDLh9V95eIkLf/fZTQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" + "@csstools/css-calc": "^1.1.5", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" }, "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" + "node": "^14 || ^16 || >=18" }, - "bin": { - "which": "bin/which" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-3.0.4.tgz", + "integrity": "sha512-yUZmbnUemgQmja7SpOZeU45+P49wNEgQguRdyTktFkZsHf7Gof+ZIYfvF6Cm+LsU1PwSupy4yUeEKKjX5+k6cQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "type-fest": "^0.20.2" + "@csstools/color-helpers": "^4.0.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-3.0.3.tgz", + "integrity": "sha512-T/npTbDuMZ3vktEMuA05p1oeVd12Sy47qZP1vFhzNMUOdXGCK9vlm0tUSIlV5DdlbTJqKqq9FhGitZH9VTKrfQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "@csstools/css-calc": "^1.1.5", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" }, "engines": { - "node": ">=10" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==" - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "devOptional": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" - }, - "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==", + "node_modules/@csstools/postcss-unset-value": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-3.0.1.tgz", + "integrity": "sha512-dbDnZ2ja2U8mbPP0Hvmt2RMEGBiF1H7oY6HYSpjteXJGihYwgxgTr6KRbbJ/V6c+4wd51M+9980qG4gKVn5ttg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "node_modules/@csstools/selector-specificity": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", + "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss-selector-parser": "^6.0.13" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "node_modules/@dual-bundle/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "node_modules/@eight04/draggable-list": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eight04/draggable-list/-/draggable-list-0.3.0.tgz", + "integrity": "sha512-3mDCUv/dCIylc7BA8VZVW8kB0Y937UqVOgORN9vyCpgmzLTfO+0Qp00vRPaXJI7MBy+Ufg7c0K08y8/a41S3cw==", "engines": { - "node": ">= 4" + "node": ">=8" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", - "dev": true + "node_modules/@eight04/read-write-lock": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eight04/read-write-lock/-/read-write-lock-0.1.0.tgz", + "integrity": "sha512-a/94gK+/GRZeTyFmJCIPlWGlgpOT3qmIRp5ByJkoxtkpspSsMbdYZKd/wNXdPYf4auRyepEM3+EkawQnscjJXQ==" }, - "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==", + "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": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "funding": { - "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": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, "engines": { - "node": ">=8" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, "dependencies": { - "is-extglob": "^2.1.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.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": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/@eslint/js": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "dev": true, "engines": { - "node": ">=0.12.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.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==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, "engines": { - "node": ">=8" + "node": ">=10.10.0" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "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": ">=0.10.0" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "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==", + "node_modules/@jridgewell/gen-mapping": { + "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": { - "argparse": "^2.0.1" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=6.0.0" } }, - "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==" - }, - "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", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } }, - "node_modules/jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "node_modules/@jridgewell/set-array": { + "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, - "dependencies": { - "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/jsonlint": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", - "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, "dependencies": { - "JSV": "^4.0.x", - "nomnom": "^1.5.x" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/JSV": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", - "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "node_modules/@jridgewell/trace-mapping": { + "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": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "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==", - "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", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/known-css-properties": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.30.0.tgz", - "integrity": "sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==" - }, - "node_modules/less": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "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==", "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" + "node": ">= 8" } }, - "node_modules/less/node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, + "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==", "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "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, + "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==", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 8" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "node_modules/@rollup/plugin-alias": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", + "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==", "dev": true, - "dependencies": { - "immediate": "~3.0.5" + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "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==", + "node_modules/@rollup/plugin-babel": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", + "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" }, "engines": { - "node": ">=10" + "node": ">=14.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "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/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" - }, - "node_modules/lz-string-unsafe": { - "version": "1.4.4-fork-1", - "resolved": "https://registry.npmjs.org/lz-string-unsafe/-/lz-string-unsafe-1.4.4-fork-1.tgz", - "integrity": "sha512-b6Ixv8tfyiZ8b0wb6VdJSLDHs3E+UbeNo81n1tTOjzXWy8ys2fleV9T3buVBIeKiMnBMo8c87FvAsRilS+BQhw==" - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "optional": true, + "node_modules/@rollup/plugin-commonjs": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz", + "integrity": "sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg==", + "dev": true, "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.1.1", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=6" + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, - "bin": { - "semver": "bin/semver" + "node_modules/@rollup/plugin-commonjs/node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" } }, - "node_modules/mathml-tag-names": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/@rollup/plugin-commonjs/node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" - }, - "node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { - "node": ">=18" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/microbuffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/microbuffer/-/microbuffer-1.0.0.tgz", - "integrity": "sha512-O/SUXauVN4x6RaEJFqSPcXNtLFL+QzJHKZlyDVYFwcDDRVca3Fa/37QXXC+4zAGGa4YhHrHxKXuuHvLDIQECtA==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", + "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", + "dev": true, "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" }, "engines": { - "node": ">=8.6" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "optional": true, - "bin": { - "mime": "cli.js" + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" }, "engines": { - "node": ">=4" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@rollup/pluginutils": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", + "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": "*" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", + "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] }, - "node_modules/needle": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz", + "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==", + "cpu": [ + "arm64" + ], + "dev": true, "optional": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } + "os": [ + "android" + ] }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz", + "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz", + "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==", + "cpu": [ + "x64" + ], + "dev": true, "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz", + "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz", + "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz", + "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz", + "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz", + "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz", + "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz", + "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz", + "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz", + "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz", + "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz", + "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz", + "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", + "dev": true, "dependencies": { - "ms": "^2.1.1" + "@types/node": "*" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dev": true, "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, - "node_modules/nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "node_modules/@types/node": { + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "dev": true, "dependencies": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" + "undici-types": "~6.19.2" } }, - "node_modules/nomnom/node_modules/ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" - }, - "node_modules/nomnom/node_modules/chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "dependencies": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - } + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true }, - "node_modules/nomnom/node_modules/strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/@xmldom/xmldom": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", + "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10.0.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" + "node": ">=0.4.0" } }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "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, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "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==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "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" - }, + "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==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "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==", - "dependencies": { - "callsites": "^3.0.0" + "node": ">=8" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "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==", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "engines": { - "node": ">= 0.10" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + "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==" }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "engines": { "node": ">=8" } }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "node_modules/autoprefixer": { + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2968,7 +3446,7 @@ }, { "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "url": "https://tidelift.com/funding/github/npm/autoprefixer" }, { "type": "github", @@ -2976,214 +3454,295 @@ } ], "dependencies": { - "nanoid": "^3.3.7", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", + "normalize-range": "^0.1.2", "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" }, "engines": { "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-6.0.2.tgz", - "integrity": "sha512-IRuCwwAAQbgaLhxQdQcIIK0dCVXg3XDUnzgKD8iwdiYdwU4rMWRWyl/W9/0nA4ihVpq5pyALiHB2veBJ0292pw==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/postcss-clamp": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", - "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=7.6.0" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { - "postcss": "^8.4.6" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/postcss-color-functional-notation": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-6.0.3.tgz", - "integrity": "sha512-2jBr3H0sk3qGh/3BkmLsOKcYyVfSlM1K2QQYVU7eW5mkg7ZOQ4aU/Rtbh7vJ9FxAfgf8iHRwXBsQkHqUxzTkXw==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" - }, - "engines": { - "node": "^14 || ^16 || >=18" + "@babel/helper-define-polyfill-provider": "^0.6.2" }, "peerDependencies": { - "postcss": "^8.4" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/postcss-color-hex-alpha": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-9.0.3.tgz", - "integrity": "sha512-7sEHU4tAS6htlxun8AB9LDrCXoljxaC34tFVRlYKcvO+18r5fvGiXgv5bQzN40+4gXLCyWSMRK5FK31244WcCA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dependencies": { - "postcss-value-parser": "^4.2.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" }, "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=8" } }, - "node_modules/postcss-color-rebeccapurple": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-9.0.2.tgz", - "integrity": "sha512-f+RDEAPW2m8UbJWkSpRfV+QxhSaQhDMihI75DVGJJh4oRIoegjheeRtINFJum9D8BqGJcvD4GLjggTvCwZ4zuA==", + "node_modules/browserslist": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "postcss-value-parser": "^4.2.0" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, - "engines": { - "node": "^14 || ^16 || >=18" + "bin": { + "browserslist": "cli.js" }, - "peerDependencies": { - "postcss": "^8.4" + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/postcss-custom-media": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-10.0.2.tgz", - "integrity": "sha512-zcEFNRmDm2fZvTPdI1pIW3W//UruMcLosmMiCdpQnrCsTRzWlKQPYMa1ud9auL0BmrryKK1+JjIGn19K0UjO/w==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001664", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz", + "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==", "dev": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/csstools" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } - ], + ] + }, + "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": { - "@csstools/cascade-layer-name-parser": "^1.0.5", - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1", - "@csstools/media-query-list-parser": "^2.1.5" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/postcss-custom-properties": { - "version": "13.3.3", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-13.3.3.tgz", - "integrity": "sha512-xLmILb2R83aG4X++iVFg8TWadOlc45xiyFHRZD6Yhhu2igrTHXL6C75AEWqx6k9lxrr9sK5rcfUI9JvTCxBTvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/codemirror": { + "version": "5.65.10", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.10.tgz", + "integrity": "sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==" + }, + "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==", "dependencies": { - "@csstools/cascade-layer-name-parser": "^1.0.6", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "postcss-value-parser": "^4.2.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=7.0.0" + } + }, + "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==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, + "node_modules/commander": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", + "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dependencies": { + "is-what": "^3.14.1" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/postcss-custom-selectors": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-7.1.6.tgz", - "integrity": "sha512-svsjWRaxqL3vAzv71dV0/65P24/FB8TbPX+lWyyf9SZ7aZm4S4NhCn7N3Bg+Z5sZunG3FS8xQ80LrCU9hb37cw==", + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/cascade-layer-name-parser": "^1.0.5", - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1", - "postcss-selector-parser": "^6.0.13" + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" }, "peerDependencies": { - "postcss": "^8.4" + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/postcss-dir-pseudo-class": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-8.0.1.tgz", - "integrity": "sha512-uULohfWBBVoFiZXgsQA24JV6FdKIidQ+ZqxOouhWwdE+qJlALbkS5ScB43ZTjPK+xUZZhlaO/NjfCt5h4IKUfw==", + "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" + } + }, + "node_modules/css-blank-pseudo": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-6.0.1.tgz", + "integrity": "sha512-goSnEITByxTzU4Oh5oJZrEWudxTqk7L6IXj1UW69pO6Hv0UdX+Vsrt02FFu5DweRh2bLu6WpX/+zsQCu5O1gKw==", "dev": true, "funding": [ { @@ -3205,10 +3764,18 @@ "postcss": "^8.4" } }, - "node_modules/postcss-double-position-gradients": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-5.0.3.tgz", - "integrity": "sha512-QKYpwmaSm6HcdS0ndAuWSNNMv78R1oSySoh3mYBmctHWr2KWcwPJVakdOyU4lvFVW0GRu9wfIQwGeM4p3xU9ow==", + "node_modules/css-functions-list": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", + "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", + "engines": { + "node": ">=12 || >=16" + } + }, + "node_modules/css-has-pseudo": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-6.0.1.tgz", + "integrity": "sha512-WwoVKqNxApfEI7dWFyaHoeFCcUPD+lPyjL6lNpRUNX7IyIUuVpawOTwwA5D0ZR6V2xQZonNPVj8kEcxzEaAQfQ==", "dev": true, "funding": [ { @@ -3221,7 +3788,8 @@ } ], "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^3.0.3", + "@csstools/selector-specificity": "^3.0.1", + "postcss-selector-parser": "^6.0.13", "postcss-value-parser": "^4.2.0" }, "engines": { @@ -3231,10 +3799,10 @@ "postcss": "^8.4" } }, - "node_modules/postcss-focus-visible": { + "node_modules/css-prefers-color-scheme": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-9.0.1.tgz", - "integrity": "sha512-N2VQ5uPz3Z9ZcqI5tmeholn4d+1H14fKXszpjogZIrFbhaq0zNAtq8sAnw6VLiqGbL8YBzsnu7K9bBkTqaRimQ==", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-9.0.1.tgz", + "integrity": "sha512-iFit06ochwCKPRiWagbTa1OAWCvWWVdEnIFd8BaRrgO8YrrNh4RAWUQTFcYX5tdFZgFl1DJ3iiULchZyEbnF4g==", "dev": true, "funding": [ { @@ -3246,9 +3814,6 @@ "url": "https://opencollective.com/csstools" } ], - "dependencies": { - "postcss-selector-parser": "^6.0.13" - }, "engines": { "node": "^14 || ^16 || >=18" }, @@ -3256,1288 +3821,4560 @@ "postcss": "^8.4" } }, - "node_modules/postcss-focus-within": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-8.0.1.tgz", - "integrity": "sha512-NFU3xcY/xwNaapVb+1uJ4n23XImoC86JNwkY/uduytSl2s9Ekc2EpzmRR63+ExitnW3Mab3Fba/wRPCT5oDILA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dependencies": { - "postcss-selector-parser": "^6.0.13" + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" }, "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/postcss-gap-properties": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-5.0.1.tgz", - "integrity": "sha512-k2z9Cnngc24c0KF4MtMuDdToROYqGMMUQGcE6V0odwjHyOHtaDBlLeRBV70y9/vF7KIbShrTRZ70JjsI1BZyWw==", + "node_modules/cssdb": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.9.1.tgz", + "integrity": "sha512-fqy6ZnNfpb8qAvTT0qijWyTsUmYThsDX2F2ctMG4ceI7mI4DtsMILSiMBiuuDnVIYTyWvCctdp9Nb08p/6m2SQ==", "dev": true, "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, { "type": "opencollective", "url": "https://opencollective.com/csstools" - } - ], - "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-image-set-function": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-6.0.2.tgz", - "integrity": "sha512-/O1xwqpJiz/apxGQi7UUfv1xUcorvkHZfvCYHPpRxxZj2WvjD0rg0+/+c+u5/Do5CpUg3XvfYxMrhcnjW1ArDQ==", - "dev": true, - "funding": [ + }, { "type": "github", "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" } - ], - "dependencies": { - "postcss-value-parser": "^4.2.0" + ] + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" }, "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=4" } }, - "node_modules/postcss-lab-function": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-6.0.8.tgz", - "integrity": "sha512-agYs7R9Z5gnX837fCkH8TEQIHdhyDsMPPnpuuENt/dxoDVAykBaqbdxIN4DagOj+ZQo20iRNNJeY3MsFcdI6Sg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/cubic2quad": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cubic2quad/-/cubic2quad-1.2.1.tgz", + "integrity": "sha512-wT5Y7mO8abrV16gnssKdmIhIbA9wSkeMzhh27jAguKrV82i24wER0vL5TGhUJ9dbJNDcigoRZ0IAHFEEEI4THQ==", + "dev": true + }, + "node_modules/db-to-cloud": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/db-to-cloud/-/db-to-cloud-0.7.0.tgz", + "integrity": "sha512-fs3FS6vMLk7E6gnuao9lJqTU+ohy6Pa9fqgZSVnoICMsCfqrnyYj+reA81xOmw9kfqVQNdtu+zZv67IJThrMvA==", "dependencies": { - "@csstools/css-color-parser": "^1.5.0", - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2", - "@csstools/postcss-progressive-custom-properties": "^3.0.3" + "@eight04/read-write-lock": "^0.1.0", + "universal-base64": "^2.1.0" }, "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=8" } }, - "node_modules/postcss-logical": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-7.0.1.tgz", - "integrity": "sha512-8GwUQZE0ri0K0HJHkDv87XOLC8DE0msc+HoWLeKdtjDZEwpZ5xuK3QdV6FhmHSQW40LPkg43QzvATRAI3LsRkg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "postcss-value-parser": "^4.2.0" + "ms": "2.1.2" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=6.0" }, - "peerDependencies": { - "postcss": "^8.4" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/postcss-nesting": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.2.tgz", - "integrity": "sha512-63PpJHSeNs93S3ZUIyi+7kKx4JqOIEJ6QYtG3x+0qA4J03+4n0iwsyA1GAHyWxsHYljQS4/4ZK1o2sMi70b5wQ==", + "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/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dependencies": { - "@csstools/selector-specificity": "^3.0.1", - "postcss-selector-parser": "^6.0.13" + "path-type": "^4.0.0" }, "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=8" } }, - "node_modules/postcss-opacity-percentage": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-2.0.0.tgz", - "integrity": "sha512-lyDrCOtntq5Y1JZpBFzIWm2wG9kbEdujpNt4NLannF+J9c8CgFIzPa80YQfdza+Y+yFfzbYj/rfoOsYsooUWTQ==", + "node_modules/docopt": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", + "integrity": "sha1-so6eIiDaXsSffqW7JKR3h0Be6xE=", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "funding": [ - { - "type": "kofi", - "url": "https://ko-fi.com/mrcgrtz" - }, - { - "type": "liberapay", - "url": "https://liberapay.com/mrcgrtz" - } - ], + "dependencies": { + "esutils": "^2.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz", + "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=6" } }, - "node_modules/postcss-overflow-shorthand": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-5.0.1.tgz", - "integrity": "sha512-XzjBYKLd1t6vHsaokMV9URBt2EwC9a7nDhpQpjoPk2HRTSQfokPfyAS/Q7AOrzUu6q+vp/GnrDBGuj/FCaRqrQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "optional": true, "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18" + "prr": "~1.0.1" }, - "peerDependencies": { - "postcss": "^8.4" + "bin": { + "errno": "cli.js" } }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "peerDependencies": { - "postcss": "^8" + "engines": { + "node": ">=6" } }, - "node_modules/postcss-place": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-9.0.1.tgz", - "integrity": "sha512-JfL+paQOgRQRMoYFc2f73pGuG/Aw3tt4vYMR6UA3cWVMxivviPTnMFnFTczUJOA4K2Zga6xgQVE+PcLs64WC8Q==", + "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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-preset-env": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.3.0.tgz", - "integrity": "sha512-ycw6doPrqV6QxDCtgiyGDef61bEfiSc59HGM4gOw/wxQxmKnhuEery61oOC/5ViENz/ycpRsuhTexs1kUBTvVw==", + "node_modules/eslint": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "@csstools/postcss-cascade-layers": "^4.0.1", - "@csstools/postcss-color-function": "^3.0.7", - "@csstools/postcss-color-mix-function": "^2.0.7", - "@csstools/postcss-exponential-functions": "^1.0.1", - "@csstools/postcss-font-format-keywords": "^3.0.0", - "@csstools/postcss-gamut-mapping": "^1.0.0", - "@csstools/postcss-gradients-interpolation-method": "^4.0.7", - "@csstools/postcss-hwb-function": "^3.0.6", - "@csstools/postcss-ic-unit": "^3.0.2", - "@csstools/postcss-initial": "^1.0.0", - "@csstools/postcss-is-pseudo-class": "^4.0.3", - "@csstools/postcss-logical-float-and-clear": "^2.0.0", - "@csstools/postcss-logical-overflow": "^1.0.0", - "@csstools/postcss-logical-overscroll-behavior": "^1.0.0", - "@csstools/postcss-logical-resize": "^2.0.0", - "@csstools/postcss-logical-viewport-units": "^2.0.3", - "@csstools/postcss-media-minmax": "^1.1.0", - "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.3", - "@csstools/postcss-nested-calc": "^3.0.0", - "@csstools/postcss-normalize-display-values": "^3.0.1", - "@csstools/postcss-oklab-function": "^3.0.7", - "@csstools/postcss-progressive-custom-properties": "^3.0.2", - "@csstools/postcss-relative-color-syntax": "^2.0.7", - "@csstools/postcss-scope-pseudo-class": "^3.0.0", - "@csstools/postcss-stepped-value-functions": "^3.0.2", - "@csstools/postcss-text-decoration-shorthand": "^3.0.3", - "@csstools/postcss-trigonometric-functions": "^3.0.2", - "@csstools/postcss-unset-value": "^3.0.0", - "autoprefixer": "^10.4.16", - "browserslist": "^4.22.1", - "css-blank-pseudo": "^6.0.0", - "css-has-pseudo": "^6.0.0", - "css-prefers-color-scheme": "^9.0.0", - "cssdb": "^7.9.0", - "postcss-attribute-case-insensitive": "^6.0.2", - "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^6.0.2", - "postcss-color-hex-alpha": "^9.0.2", - "postcss-color-rebeccapurple": "^9.0.1", - "postcss-custom-media": "^10.0.2", - "postcss-custom-properties": "^13.3.2", - "postcss-custom-selectors": "^7.1.6", - "postcss-dir-pseudo-class": "^8.0.0", - "postcss-double-position-gradients": "^5.0.2", - "postcss-focus-visible": "^9.0.0", - "postcss-focus-within": "^8.0.0", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^5.0.0", - "postcss-image-set-function": "^6.0.1", - "postcss-lab-function": "^6.0.7", - "postcss-logical": "^7.0.0", - "postcss-nesting": "^12.0.1", - "postcss-opacity-percentage": "^2.0.0", - "postcss-overflow-shorthand": "^5.0.0", - "postcss-page-break": "^3.0.4", - "postcss-place": "^9.0.0", - "postcss-pseudo-class-any-link": "^9.0.0", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^7.0.1", - "postcss-value-parser": "^4.2.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "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": "^14 || ^16 || >=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-9.0.1.tgz", - "integrity": "sha512-cKYGGZ9yzUZi+dZd7XT2M8iSDfo+T2Ctbpiizf89uBTBfIpZpjvTavzIJXpCReMVXSKROqzpxClNu6fz4DHM0Q==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "dependencies": { - "postcss-selector-parser": "^6.0.13" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "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, - "peerDependencies": { - "postcss": "^8.0.3" - } - }, - "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==" - }, - "node_modules/postcss-safe-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", - "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "engines": { - "node": ">=18.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "postcss": "^8.4.31" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/postcss-selector-not": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-7.0.1.tgz", - "integrity": "sha512-1zT5C27b/zeJhchN7fP0kBr16Cc61mu7Si9uWWLoA3Px/D9tIJPKchJCkUH3tPO5D0pCFmGeApAv8XpXBQJ8SQ==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^14 || ^16 || >=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "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" }, - "peerDependencies": { - "postcss": "^8.4" + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "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/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "node_modules/event-lite": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.2.tgz", + "integrity": "sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "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==", + "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-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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", + "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", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz", + "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==", + "dev": true, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "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", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==" + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "devOptional": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "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/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "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==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "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==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "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": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "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-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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==", + "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", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "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==" + }, + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "node_modules/jsonlint": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", + "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", + "dependencies": { + "JSV": "^4.0.x", + "nomnom": "^1.5.x" + } + }, + "node_modules/JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "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==", + "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", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/known-css-properties": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.30.0.tgz", + "integrity": "sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==" + }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less/node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "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/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "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/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string-unsafe": { + "version": "1.4.4-fork-1", + "resolved": "https://registry.npmjs.org/lz-string-unsafe/-/lz-string-unsafe-1.4.4-fork-1.tgz", + "integrity": "sha512-b6Ixv8tfyiZ8b0wb6VdJSLDHs3E+UbeNo81n1tTOjzXWy8ys2fleV9T3buVBIeKiMnBMo8c87FvAsRilS+BQhw==" + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/mathml-tag-names": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", + "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/microbuffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/microbuffer/-/microbuffer-1.0.0.tgz", + "integrity": "sha512-O/SUXauVN4x6RaEJFqSPcXNtLFL+QzJHKZlyDVYFwcDDRVca3Fa/37QXXC+4zAGGa4YhHrHxKXuuHvLDIQECtA==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dependencies": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + } + }, + "node_modules/nomnom/node_modules/ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" + }, + "node_modules/nomnom/node_modules/chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dependencies": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + } + }, + "node_modules/nomnom/node_modules/strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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/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/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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==", + "dependencies": { + "callsites": "^3.0.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-6.0.2.tgz", + "integrity": "sha512-IRuCwwAAQbgaLhxQdQcIIK0dCVXg3XDUnzgKD8iwdiYdwU4rMWRWyl/W9/0nA4ihVpq5pyALiHB2veBJ0292pw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-6.0.3.tgz", + "integrity": "sha512-2jBr3H0sk3qGh/3BkmLsOKcYyVfSlM1K2QQYVU7eW5mkg7ZOQ4aU/Rtbh7vJ9FxAfgf8iHRwXBsQkHqUxzTkXw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-9.0.3.tgz", + "integrity": "sha512-7sEHU4tAS6htlxun8AB9LDrCXoljxaC34tFVRlYKcvO+18r5fvGiXgv5bQzN40+4gXLCyWSMRK5FK31244WcCA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-9.0.2.tgz", + "integrity": "sha512-f+RDEAPW2m8UbJWkSpRfV+QxhSaQhDMihI75DVGJJh4oRIoegjheeRtINFJum9D8BqGJcvD4GLjggTvCwZ4zuA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-media": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-10.0.2.tgz", + "integrity": "sha512-zcEFNRmDm2fZvTPdI1pIW3W//UruMcLosmMiCdpQnrCsTRzWlKQPYMa1ud9auL0BmrryKK1+JjIGn19K0UjO/w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^1.0.5", + "@csstools/css-parser-algorithms": "^2.3.2", + "@csstools/css-tokenizer": "^2.2.1", + "@csstools/media-query-list-parser": "^2.1.5" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-13.3.3.tgz", + "integrity": "sha512-xLmILb2R83aG4X++iVFg8TWadOlc45xiyFHRZD6Yhhu2igrTHXL6C75AEWqx6k9lxrr9sK5rcfUI9JvTCxBTvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^1.0.6", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-7.1.6.tgz", + "integrity": "sha512-svsjWRaxqL3vAzv71dV0/65P24/FB8TbPX+lWyyf9SZ7aZm4S4NhCn7N3Bg+Z5sZunG3FS8xQ80LrCU9hb37cw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^1.0.5", + "@csstools/css-parser-algorithms": "^2.3.2", + "@csstools/css-tokenizer": "^2.2.1", + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-8.0.1.tgz", + "integrity": "sha512-uULohfWBBVoFiZXgsQA24JV6FdKIidQ+ZqxOouhWwdE+qJlALbkS5ScB43ZTjPK+xUZZhlaO/NjfCt5h4IKUfw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-5.0.3.tgz", + "integrity": "sha512-QKYpwmaSm6HcdS0ndAuWSNNMv78R1oSySoh3mYBmctHWr2KWcwPJVakdOyU4lvFVW0GRu9wfIQwGeM4p3xU9ow==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^3.0.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-9.0.1.tgz", + "integrity": "sha512-N2VQ5uPz3Z9ZcqI5tmeholn4d+1H14fKXszpjogZIrFbhaq0zNAtq8sAnw6VLiqGbL8YBzsnu7K9bBkTqaRimQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-8.0.1.tgz", + "integrity": "sha512-NFU3xcY/xwNaapVb+1uJ4n23XImoC86JNwkY/uduytSl2s9Ekc2EpzmRR63+ExitnW3Mab3Fba/wRPCT5oDILA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-5.0.1.tgz", + "integrity": "sha512-k2z9Cnngc24c0KF4MtMuDdToROYqGMMUQGcE6V0odwjHyOHtaDBlLeRBV70y9/vF7KIbShrTRZ70JjsI1BZyWw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-6.0.2.tgz", + "integrity": "sha512-/O1xwqpJiz/apxGQi7UUfv1xUcorvkHZfvCYHPpRxxZj2WvjD0rg0+/+c+u5/Do5CpUg3XvfYxMrhcnjW1ArDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-lab-function": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-6.0.8.tgz", + "integrity": "sha512-agYs7R9Z5gnX837fCkH8TEQIHdhyDsMPPnpuuENt/dxoDVAykBaqbdxIN4DagOj+ZQo20iRNNJeY3MsFcdI6Sg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.5.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/postcss-progressive-custom-properties": "^3.0.3" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-logical": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-7.0.1.tgz", + "integrity": "sha512-8GwUQZE0ri0K0HJHkDv87XOLC8DE0msc+HoWLeKdtjDZEwpZ5xuK3QdV6FhmHSQW40LPkg43QzvATRAI3LsRkg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.2.tgz", + "integrity": "sha512-63PpJHSeNs93S3ZUIyi+7kKx4JqOIEJ6QYtG3x+0qA4J03+4n0iwsyA1GAHyWxsHYljQS4/4ZK1o2sMi70b5wQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^3.0.1", + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-2.0.0.tgz", + "integrity": "sha512-lyDrCOtntq5Y1JZpBFzIWm2wG9kbEdujpNt4NLannF+J9c8CgFIzPa80YQfdza+Y+yFfzbYj/rfoOsYsooUWTQ==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-5.0.1.tgz", + "integrity": "sha512-XzjBYKLd1t6vHsaokMV9URBt2EwC9a7nDhpQpjoPk2HRTSQfokPfyAS/Q7AOrzUu6q+vp/GnrDBGuj/FCaRqrQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-9.0.1.tgz", + "integrity": "sha512-JfL+paQOgRQRMoYFc2f73pGuG/Aw3tt4vYMR6UA3cWVMxivviPTnMFnFTczUJOA4K2Zga6xgQVE+PcLs64WC8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.3.0.tgz", + "integrity": "sha512-ycw6doPrqV6QxDCtgiyGDef61bEfiSc59HGM4gOw/wxQxmKnhuEery61oOC/5ViENz/ycpRsuhTexs1kUBTvVw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-cascade-layers": "^4.0.1", + "@csstools/postcss-color-function": "^3.0.7", + "@csstools/postcss-color-mix-function": "^2.0.7", + "@csstools/postcss-exponential-functions": "^1.0.1", + "@csstools/postcss-font-format-keywords": "^3.0.0", + "@csstools/postcss-gamut-mapping": "^1.0.0", + "@csstools/postcss-gradients-interpolation-method": "^4.0.7", + "@csstools/postcss-hwb-function": "^3.0.6", + "@csstools/postcss-ic-unit": "^3.0.2", + "@csstools/postcss-initial": "^1.0.0", + "@csstools/postcss-is-pseudo-class": "^4.0.3", + "@csstools/postcss-logical-float-and-clear": "^2.0.0", + "@csstools/postcss-logical-overflow": "^1.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^1.0.0", + "@csstools/postcss-logical-resize": "^2.0.0", + "@csstools/postcss-logical-viewport-units": "^2.0.3", + "@csstools/postcss-media-minmax": "^1.1.0", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.3", + "@csstools/postcss-nested-calc": "^3.0.0", + "@csstools/postcss-normalize-display-values": "^3.0.1", + "@csstools/postcss-oklab-function": "^3.0.7", + "@csstools/postcss-progressive-custom-properties": "^3.0.2", + "@csstools/postcss-relative-color-syntax": "^2.0.7", + "@csstools/postcss-scope-pseudo-class": "^3.0.0", + "@csstools/postcss-stepped-value-functions": "^3.0.2", + "@csstools/postcss-text-decoration-shorthand": "^3.0.3", + "@csstools/postcss-trigonometric-functions": "^3.0.2", + "@csstools/postcss-unset-value": "^3.0.0", + "autoprefixer": "^10.4.16", + "browserslist": "^4.22.1", + "css-blank-pseudo": "^6.0.0", + "css-has-pseudo": "^6.0.0", + "css-prefers-color-scheme": "^9.0.0", + "cssdb": "^7.9.0", + "postcss-attribute-case-insensitive": "^6.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^6.0.2", + "postcss-color-hex-alpha": "^9.0.2", + "postcss-color-rebeccapurple": "^9.0.1", + "postcss-custom-media": "^10.0.2", + "postcss-custom-properties": "^13.3.2", + "postcss-custom-selectors": "^7.1.6", + "postcss-dir-pseudo-class": "^8.0.0", + "postcss-double-position-gradients": "^5.0.2", + "postcss-focus-visible": "^9.0.0", + "postcss-focus-within": "^8.0.0", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^5.0.0", + "postcss-image-set-function": "^6.0.1", + "postcss-lab-function": "^6.0.7", + "postcss-logical": "^7.0.0", + "postcss-nesting": "^12.0.1", + "postcss-opacity-percentage": "^2.0.0", + "postcss-overflow-shorthand": "^5.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^9.0.0", + "postcss-pseudo-class-any-link": "^9.0.0", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^7.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-9.0.1.tgz", + "integrity": "sha512-cKYGGZ9yzUZi+dZd7XT2M8iSDfo+T2Ctbpiizf89uBTBfIpZpjvTavzIJXpCReMVXSKROqzpxClNu6fz4DHM0Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-resolve-nested-selector": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", + "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==" + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", + "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-not": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-7.0.1.tgz", + "integrity": "sha512-1zT5C27b/zeJhchN7fP0kBr16Cc61mu7Si9uWWLoA3Px/D9tIJPKchJCkUH3tPO5D0pCFmGeApAv8XpXBQJ8SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "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", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "optional": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "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==", + "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", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==" + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "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", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz", + "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.22.5", + "@rollup/rollup-android-arm64": "4.22.5", + "@rollup/rollup-darwin-arm64": "4.22.5", + "@rollup/rollup-darwin-x64": "4.22.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.5", + "@rollup/rollup-linux-arm-musleabihf": "4.22.5", + "@rollup/rollup-linux-arm64-gnu": "4.22.5", + "@rollup/rollup-linux-arm64-musl": "4.22.5", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5", + "@rollup/rollup-linux-riscv64-gnu": "4.22.5", + "@rollup/rollup-linux-s390x-gnu": "4.22.5", + "@rollup/rollup-linux-x64-gnu": "4.22.5", + "@rollup/rollup-linux-x64-musl": "4.22.5", + "@rollup/rollup-win32-arm64-msvc": "4.22.5", + "@rollup/rollup-win32-ia32-msvc": "4.22.5", + "@rollup/rollup-win32-x64-msvc": "4.22.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-copy": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", + "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/rollup-plugin-copy/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/rollup-plugin-copy/node_modules/globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-copy/node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup-plugin-copy/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/rollup-plugin-copy/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/rollup-plugin-css-only": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz", + "integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "5" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "rollup": "<5" + } + }, + "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==", + "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.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "optional": true + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "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" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "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" + } + }, + "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 + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/stylelint": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.5.0.tgz", + "integrity": "sha512-IlCBtVrG+qTy3v+tZTk50W8BIomjY/RUuzdrDqdnlCYwVuzXtPbiGfxYqtyYAyOMcb+195zRsuHn6tgfPmFfbw==", + "dependencies": { + "@csstools/css-parser-algorithms": "^2.6.1", + "@csstools/css-tokenizer": "^2.2.4", + "@csstools/media-query-list-parser": "^2.1.9", + "@csstools/selector-specificity": "^3.0.3", + "@dual-bundle/import-meta-resolve": "^4.0.0", + "balanced-match": "^2.0.0", + "colord": "^2.9.3", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.2", + "css-tree": "^2.3.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^8.0.0", + "global-modules": "^2.0.0", + "globby": "^11.1.0", + "globjoin": "^0.1.4", + "html-tags": "^3.3.1", + "ignore": "^5.3.1", + "imurmurhash": "^0.1.4", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.30.0", + "mathml-tag-names": "^2.1.3", + "meow": "^13.2.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.38", + "postcss-resolve-nested-selector": "^0.1.1", + "postcss-safe-parser": "^7.0.0", + "postcss-selector-parser": "^6.0.16", + "postcss-value-parser": "^4.2.0", + "resolve-from": "^5.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^7.1.0", + "supports-hyperlinks": "^3.0.0", + "svg-tags": "^1.0.0", + "table": "^6.8.2", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + } + }, + "node_modules/stylelint-bundle": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/stylelint-bundle/-/stylelint-bundle-16.5.0.tgz", + "integrity": "sha512-rKdEiW7E2VZcKrapaqtJkzn+oKYpgkeAwInowM/BIAB5lHZ0564B6/PQBYsfV+ldAU6yZp1T/Two0sUPnTYVxA==", + "dependencies": { + "stylelint": "^16.5.0", + "sugarss": "^4.0.1" + }, + "engines": { + "node": ">= 14.5.0" + } + }, + "node_modules/stylelint/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==" + }, + "node_modules/stylelint/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==", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/stylelint/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==", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/stylelint/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/stylelint/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stylus": { + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.63.0.tgz", + "integrity": "sha512-OMlgrTCPzE/ibtRMoeLVhOY0RcNuNWh0rhAVqeKnk/QwcuUKQbnqhZ1kg2vzD8VU/6h3FoPTq4RJPHgLBvX6Bw==", + "dependencies": { + "@adobe/css-tools": "~4.3.3", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.3.0", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://opencollective.com/stylus" + } + }, + "node_modules/stylus-lang-bundle": { + "version": "0.63.1", + "resolved": "https://registry.npmjs.org/stylus-lang-bundle/-/stylus-lang-bundle-0.63.1.tgz", + "integrity": "sha512-q7WGvN0sYGqHVhb8yTppQqfym5s+Os/4auGfrddAbsicOEpqzL1n1m38yds1cMGKPvvFr4Ws95WvI56klqhKsQ==", + "dependencies": { + "event-lite": "^0.1.2", + "path-browserify": "^1.0.1", + "stylus": "0.63.0", + "tiny-sha1": "^0.2.1" + } + }, + "node_modules/stylus/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/sugarss": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-4.0.1.tgz", + "integrity": "sha512-WCjS5NfuVJjkQzK10s8WOBY+hhDxxNt/N6ZaGwxFZ+wN3/lKKFSaaKUNecULcTTvE4urLcKaZFQD8vO0mOZujw==", + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", + "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==" + }, + "node_modules/svg2ttf": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg2ttf/-/svg2ttf-6.0.3.tgz", + "integrity": "sha512-CgqMyZrbOPpc+WqH7aga4JWkDPso23EgypLsbQ6gN3uoPWwwiLjXvzgrwGADBExvCRJrWFzAeK1bSoSpE7ixSQ==", + "dev": true, + "dependencies": { + "@xmldom/xmldom": "^0.7.2", + "argparse": "^2.0.1", + "cubic2quad": "^1.2.1", + "lodash": "^4.17.10", + "microbuffer": "^1.0.0", + "svgpath": "^2.1.5" + }, + "bin": { + "svg2ttf": "svg2ttf.js" + } + }, + "node_modules/svgicons2svgfont": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/svgicons2svgfont/-/svgicons2svgfont-12.0.0.tgz", + "integrity": "sha512-fjyDkhiG0M1TPBtZzD12QV3yDcG2fUgiqHPOCYzf7hHE40Hl3GhnE6P1njsJCCByhwM7MiufyDW3L7IOR5dg9w==", + "dev": true, + "dependencies": { + "commander": "^9.3.0", + "glob": "^8.0.3", + "sax": "^1.2.4", + "svg-pathdata": "^6.0.3" + }, + "bin": { + "svgicons2svgfont": "bin/svgicons2svgfont.js" + }, + "engines": { + "node": ">=16.15.0" + } + }, + "node_modules/svgicons2svgfont/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/svgicons2svgfont/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/svgicons2svgfont/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/svgpath": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.6.0.tgz", + "integrity": "sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==", + "dev": true, + "funding": { + "url": "https://github.com/fontello/svg2ttf?sponsor=1" + } + }, + "node_modules/sync-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sync-version/-/sync-version-1.0.1.tgz", + "integrity": "sha1-Y6aglKmigcUqgA1obqu5ZgH4igs=", + "dev": true, + "dependencies": { + "docopt": "^0.6.2" + } + }, + "node_modules/table": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "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/table/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==" + }, + "node_modules/terser": { + "version": "5.34.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", + "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/tiny-sha1": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tiny-sha1/-/tiny-sha1-0.2.1.tgz", + "integrity": "sha1-onRkudPxv4LpMaRrGqPfmcqSbF4=" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "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-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==" + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universal-base64": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/universal-base64/-/universal-base64-2.1.0.tgz", + "integrity": "sha512-WeOkACVnIXJZr/qlv7++Rl1zuZOHN96v2yS5oleUuv8eJOs5j9M5U3xQEIoWqn1OzIuIcgw0fswxWnUVGDfW6g==" + }, + "node_modules/universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/usercss-meta": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/usercss-meta/-/usercss-meta-0.12.0.tgz", + "integrity": "sha512-zKrXCKdpeIwtVe87omxGo9URf+7mbozduMZEg79dmT4KB3XJwfIkEi/Uk0PcTwR/nZLtAK1+k7isgbGB/g6E7Q==", + "engines": { + "node": ">=8.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/webext-launch-web-auth-flow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/webext-launch-web-auth-flow/-/webext-launch-web-auth-flow-0.1.1.tgz", + "integrity": "sha512-e8G0W+Js6P1i/aD0XoSkWfodhdTf01fiqDQk+wcSkVPkzmqDxhzKkBpJ1Y2dz3pR4Ocve7z/yx+mMI8jsRAiPg==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.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" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "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" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==" + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@babel/code-frame": { + "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==", + "requires": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + } + }, + "@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "dev": true + }, + "@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "peer": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "dev": true, + "requires": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "requires": { + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + } + }, + "@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "requires": { + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==" + }, + "@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dev": true, + "requires": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + } + }, + "@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + } + }, + "@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "requires": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.25.6" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "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==", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dev": true, - "engines": { - "node": ">= 0.8.0" + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "optional": true + "@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" } }, - "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==" + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "requires": {} }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" } }, - "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==", - "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" + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "optional": true + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } }, - "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + "@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.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==", + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" } }, - "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 + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "engines": { - "node": ">=0.10.0" + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" } }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, - "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==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, - "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==", + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, - "node_modules/stylelint": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.5.0.tgz", - "integrity": "sha512-IlCBtVrG+qTy3v+tZTk50W8BIomjY/RUuzdrDqdnlCYwVuzXtPbiGfxYqtyYAyOMcb+195zRsuHn6tgfPmFfbw==", - "dependencies": { - "@csstools/css-parser-algorithms": "^2.6.1", - "@csstools/css-tokenizer": "^2.2.4", - "@csstools/media-query-list-parser": "^2.1.9", - "@csstools/selector-specificity": "^3.0.3", - "@dual-bundle/import-meta-resolve": "^4.0.0", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^9.0.0", - "css-functions-list": "^3.2.2", - "css-tree": "^2.3.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^8.0.0", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.3.1", - "ignore": "^5.3.1", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.30.0", - "mathml-tag-names": "^2.1.3", - "meow": "^13.2.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.38", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^7.0.0", - "postcss-selector-parser": "^6.0.16", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^7.1.0", - "supports-hyperlinks": "^3.0.0", - "svg-tags": "^1.0.0", - "table": "^6.8.2", - "write-file-atomic": "^5.0.1" - }, - "bin": { - "stylelint": "bin/stylelint.mjs" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" + "@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/stylelint-bundle": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/stylelint-bundle/-/stylelint-bundle-16.5.0.tgz", - "integrity": "sha512-rKdEiW7E2VZcKrapaqtJkzn+oKYpgkeAwInowM/BIAB5lHZ0564B6/PQBYsfV+ldAU6yZp1T/Two0sUPnTYVxA==", - "dependencies": { - "stylelint": "^16.5.0", - "sugarss": "^4.0.1" - }, - "engines": { - "node": ">= 14.5.0" + "@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" } }, - "node_modules/stylelint/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" } }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==" + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } }, - "node_modules/stylelint/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==", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" } }, - "node_modules/stylelint/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==", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" } }, - "node_modules/stylelint/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "engines": { - "node": ">=8" + "@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, - "node_modules/stylelint/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" + "@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "dependencies": { + "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 + } } }, - "node_modules/stylus": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.63.0.tgz", - "integrity": "sha512-OMlgrTCPzE/ibtRMoeLVhOY0RcNuNWh0rhAVqeKnk/QwcuUKQbnqhZ1kg2vzD8VU/6h3FoPTq4RJPHgLBvX6Bw==", - "dependencies": { - "@adobe/css-tools": "~4.3.3", - "debug": "^4.3.2", - "glob": "^7.1.6", - "sax": "~1.3.0", - "source-map": "^0.7.3" - }, - "bin": { - "stylus": "bin/stylus" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://opencollective.com/stylus" + "@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" } }, - "node_modules/stylus-lang-bundle": { - "version": "0.63.1", - "resolved": "https://registry.npmjs.org/stylus-lang-bundle/-/stylus-lang-bundle-0.63.1.tgz", - "integrity": "sha512-q7WGvN0sYGqHVhb8yTppQqfym5s+Os/4auGfrddAbsicOEpqzL1n1m38yds1cMGKPvvFr4Ws95WvI56klqhKsQ==", - "dependencies": { - "event-lite": "^0.1.2", - "path-browserify": "^1.0.1", - "stylus": "0.63.0", - "tiny-sha1": "^0.2.1" + "@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" } }, - "node_modules/stylus/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" + "@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/sugarss": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-4.0.1.tgz", - "integrity": "sha512-WCjS5NfuVJjkQzK10s8WOBY+hhDxxNt/N6ZaGwxFZ+wN3/lKKFSaaKUNecULcTTvE4urLcKaZFQD8vO0mOZujw==", - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" + "@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" } }, - "node_modules/supports-hyperlinks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", - "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=14.18" + "@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, - "node_modules/svg-pathdata": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", - "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", "dev": true, - "engines": { - "node": ">=12.0.0" + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==" + "@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } }, - "node_modules/svg2ttf": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/svg2ttf/-/svg2ttf-6.0.3.tgz", - "integrity": "sha512-CgqMyZrbOPpc+WqH7aga4JWkDPso23EgypLsbQ6gN3uoPWwwiLjXvzgrwGADBExvCRJrWFzAeK1bSoSpE7ixSQ==", + "@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", "dev": true, - "dependencies": { - "@xmldom/xmldom": "^0.7.2", - "argparse": "^2.0.1", - "cubic2quad": "^1.2.1", - "lodash": "^4.17.10", - "microbuffer": "^1.0.0", - "svgpath": "^2.1.5" - }, - "bin": { - "svg2ttf": "svg2ttf.js" + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" } }, - "node_modules/svgicons2svgfont": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/svgicons2svgfont/-/svgicons2svgfont-12.0.0.tgz", - "integrity": "sha512-fjyDkhiG0M1TPBtZzD12QV3yDcG2fUgiqHPOCYzf7hHE40Hl3GhnE6P1njsJCCByhwM7MiufyDW3L7IOR5dg9w==", + "@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, - "dependencies": { - "commander": "^9.3.0", - "glob": "^8.0.3", - "sax": "^1.2.4", - "svg-pathdata": "^6.0.3" - }, - "bin": { - "svgicons2svgfont": "bin/svgicons2svgfont.js" - }, - "engines": { - "node": ">=16.15.0" + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" } }, - "node_modules/svgicons2svgfont/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, - "node_modules/svgicons2svgfont/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/svgicons2svgfont/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" + "requires": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/svgpath": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.6.0.tgz", - "integrity": "sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==", + "@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", "dev": true, - "funding": { - "url": "https://github.com/fontello/svg2ttf?sponsor=1" + "requires": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" } }, - "node_modules/sync-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sync-version/-/sync-version-1.0.1.tgz", - "integrity": "sha1-Y6aglKmigcUqgA1obqu5ZgH4igs=", + "@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dev": true, - "dependencies": { - "docopt": "^0.6.2" + "requires": { + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" } }, - "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" + "@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", - "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" + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/table/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==" + "@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } }, - "node_modules/tiny-sha1": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tiny-sha1/-/tiny-sha1-0.2.1.tgz", - "integrity": "sha1-onRkudPxv4LpMaRrGqPfmcqSbF4=" + "@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" + "@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } }, - "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==", + "@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==" + "@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + } }, - "node_modules/universal-base64": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/universal-base64/-/universal-base64-2.1.0.tgz", - "integrity": "sha512-WeOkACVnIXJZr/qlv7++Rl1zuZOHN96v2yS5oleUuv8eJOs5j9M5U3xQEIoWqn1OzIuIcgw0fswxWnUVGDfW6g==" + "@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } }, - "node_modules/universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", - "dev": true + "@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" + "@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/usercss-meta": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/usercss-meta/-/usercss-meta-0.12.0.tgz", - "integrity": "sha512-zKrXCKdpeIwtVe87omxGo9URf+7mbozduMZEg79dmT4KB3XJwfIkEi/Uk0PcTwR/nZLtAK1+k7isgbGB/g6E7Q==", - "engines": { - "node": ">=8.3" + "@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + } }, - "node_modules/webext-launch-web-auth-flow": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/webext-launch-web-auth-flow/-/webext-launch-web-auth-flow-0.1.1.tgz", - "integrity": "sha512-e8G0W+Js6P1i/aD0XoSkWfodhdTf01fiqDQk+wcSkVPkzmqDxhzKkBpJ1Y2dz3pR4Ocve7z/yx+mMI8jsRAiPg==" + "@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" } }, - "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==", + "@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true }, - "@adobe/css-tools": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", - "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==" + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true }, - "@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dev": true, "requires": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" + "regenerator-runtime": "^0.14.0" } }, - "@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==" + "@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + } }, - "@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.24.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } + "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 } } }, + "@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + } + }, "@csstools/cascade-layer-name-parser": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.6.tgz", @@ -4920,87 +8757,358 @@ "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true }, - "@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@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 + }, + "@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "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, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "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 + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "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, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@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==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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==" + }, + "@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==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@rollup/plugin-alias": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", + "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==", + "dev": true, + "requires": {} + }, + "@rollup/plugin-babel": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", + "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + } + }, + "@rollup/plugin-commonjs": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz", + "integrity": "sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.1.1", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^2.3.1" + }, + "dependencies": { + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", + "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + } + }, + "@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "requires": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + } + }, + "@rollup/pluginutils": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", + "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "dependencies": { + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + } + } + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", + "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz", + "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz", + "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz", + "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz", + "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz", + "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz", + "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz", + "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz", + "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz", + "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz", + "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==", "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } + "optional": true }, - "@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 + "@rollup/rollup-linux-x64-gnu": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz", + "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==", + "dev": true, + "optional": true }, - "@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "@rollup/rollup-linux-x64-musl": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz", + "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==", + "dev": true, + "optional": true }, - "@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==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz", + "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==", + "dev": true, + "optional": true }, - "@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==" + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz", + "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==", + "dev": true, + "optional": true }, - "@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==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } + "@rollup/rollup-win32-x64-msvc": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz", + "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==", + "dev": true, + "optional": true }, - "@types/chrome": { - "version": "0.0.263", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.263.tgz", - "integrity": "sha512-As0vzv99ov3M6ZR7R6VzhMWFZXkPMrFrCEXXVrMN576Cm70fTkj7Df2CF+qEo170JepX50pd11cX6O4DSAtl2Q==", + "@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", "dev": true, "requires": { - "@types/filesystem": "*", - "@types/har-format": "*" + "@types/node": "*" } }, - "@types/filesystem": { - "version": "0.0.36", - "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", - "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dev": true, "requires": { - "@types/filewriter": "*" + "@types/minimatch": "*", + "@types/node": "*" } }, - "@types/filewriter": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", - "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, - "@types/firefox-webext-browser": { - "version": "120.0.3", - "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-120.0.3.tgz", - "integrity": "sha512-APbBSxOvFMbKwXy/4YrEVa5Di6N0C9yl4w0WA0xzdkOrChAfPQ/KlcC8QLyhemHCHpF1CB/zHy52+oUQurViOg==", - "dev": true + "@types/node": { + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "dev": true, + "requires": { + "undici-types": "~6.19.2" + } }, - "@types/har-format": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.15.tgz", - "integrity": "sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==", + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true }, "@ungap/structured-clone": { @@ -5082,6 +9190,36 @@ "postcss-value-parser": "^4.2.0" } }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -5105,26 +9243,32 @@ } }, "browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" } }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "caniuse-lite": { - "version": "1.0.30001570", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", - "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", + "version": "1.0.30001664", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz", + "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==", "dev": true }, "chalk": { @@ -5160,17 +9304,36 @@ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" }, + "colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, "commander": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, "copy-anything": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", @@ -5179,6 +9342,15 @@ "is-what": "^3.14.1" } }, + "core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "requires": { + "browserslist": "^4.23.3" + } + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -5288,6 +9460,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -5312,9 +9490,9 @@ } }, "electron-to-chromium": { - "version": "1.4.615", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz", - "integrity": "sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz", + "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==", "dev": true }, "emoji-regex": { @@ -5345,9 +9523,9 @@ } }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true }, "escape-string-regexp": { @@ -5453,6 +9631,12 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5516,6 +9700,13 @@ "reusify": "^1.0.4" } }, + "fdir": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz", + "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==", + "dev": true, + "requires": {} + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5588,6 +9779,26 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5687,6 +9898,15 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", @@ -5750,6 +9970,15 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "requires": { + "hasown": "^2.0.2" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5768,6 +9997,12 @@ "is-extglob": "^2.1.1" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5813,6 +10048,12 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5835,6 +10076,13 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true + }, "jsonfile": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", @@ -5970,6 +10218,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5981,6 +10235,15 @@ "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, "lz-string-unsafe": { "version": "1.4.4-fork-1", "resolved": "https://registry.npmjs.org/lz-string-unsafe/-/lz-string-unsafe-1.4.4-fork-1.tgz", @@ -6037,6 +10300,13 @@ "requires": { "braces": "^3.0.3", "picomatch": "^2.3.1" + }, + "dependencies": { + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + } } }, "mime": { @@ -6101,9 +10371,9 @@ } }, "node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "nomnom": { @@ -6240,20 +10510,29 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" }, "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "optional": true, + "peer": true }, "pify": { "version": "4.0.1", @@ -6624,11 +10903,92 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -6648,6 +11008,104 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz", + "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.22.5", + "@rollup/rollup-android-arm64": "4.22.5", + "@rollup/rollup-darwin-arm64": "4.22.5", + "@rollup/rollup-darwin-x64": "4.22.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.5", + "@rollup/rollup-linux-arm-musleabihf": "4.22.5", + "@rollup/rollup-linux-arm64-gnu": "4.22.5", + "@rollup/rollup-linux-arm64-musl": "4.22.5", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5", + "@rollup/rollup-linux-riscv64-gnu": "4.22.5", + "@rollup/rollup-linux-s390x-gnu": "4.22.5", + "@rollup/rollup-linux-x64-gnu": "4.22.5", + "@rollup/rollup-linux-x64-musl": "4.22.5", + "@rollup/rollup-win32-arm64-msvc": "4.22.5", + "@rollup/rollup-win32-ia32-msvc": "4.22.5", + "@rollup/rollup-win32-x64-msvc": "4.22.5", + "@types/estree": "1.0.6", + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-copy": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", + "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", + "dev": true, + "requires": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "rollup-plugin-css-only": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz", + "integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "5" + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6673,6 +11131,21 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -6714,17 +11187,33 @@ "is-fullwidth-code-point": "^3.0.0" } }, + "smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true + "devOptional": true }, "source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6908,6 +11397,12 @@ "supports-color": "^7.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "svg-pathdata": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", @@ -7023,6 +11518,26 @@ } } }, + "terser": { + "version": "5.34.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", + "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -7034,6 +11549,12 @@ "resolved": "https://registry.npmjs.org/tiny-sha1/-/tiny-sha1-0.2.1.tgz", "integrity": "sha1-onRkudPxv4LpMaRrGqPfmcqSbF4=" }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7073,6 +11594,40 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==" }, + "undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, "universal-base64": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/universal-base64/-/universal-base64-2.1.0.tgz", @@ -7085,13 +11640,13 @@ "dev": true }, "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" } }, "uri-js": { @@ -7156,6 +11711,12 @@ "signal-exit": "^4.0.1" } }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 5c632c47c21..4b9adb8e21a 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "license": "GPL-3.0-only", "repository": "openstyles/stylus", "author": "Stylus Team", - "dependenciesNotes": { - "codemirror": "WARNING! Always use an exact version and test it for a while before releasing" - }, + "browserslist": [ + "Chrome >= 61", + "Firefox >= 57" + ], "dependencies": { "@eight04/draggable-list": "^0.3.0", "codemirror": "5.65.10", @@ -21,8 +22,12 @@ "webext-launch-web-auth-flow": "^0.1.1" }, "devDependencies": { - "@types/chrome": "^0.0.263", - "@types/firefox-webext-browser": "^120.0.3", + "@babel/preset-env": "^7.25.4", + "@rollup/plugin-alias": "^5.1.1", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^28.0.0", + "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-terser": "^0.4.4", "chalk": "^4.1.2", "eslint": "^8.48.0", "fast-glob": "^3.3.1", @@ -31,6 +36,9 @@ "node-fetch": "^2.7.0", "postcss": "^8.4.32", "postcss-preset-env": "^9.3.0", + "rollup": "^4.22.5", + "rollup-plugin-copy": "^3.5.0", + "rollup-plugin-css-only": "^4.5.2", "svg2ttf": "^6.0.3", "svgicons2svgfont": "^12.0.0", "sync-version": "^1.0.1" @@ -40,6 +48,8 @@ "test": "node tools/test.js && npm run lint", "update-locales": "tx pull --all && node tools/fix-transifex.js && git commit -m \"update locales\" _locales", "update-transifex": "tx push -s", + "build": "rollup -c", + "watch": "rollup -c -w", "build-chrome": "npm test && node tools/build.js chrome", "build-firefox": "npm test && node tools/build.js firefox", "build-icons": "node tools/build-icons", diff --git a/rollup.config.mjs b/rollup.config.mjs new file mode 100644 index 00000000000..e2852593973 --- /dev/null +++ b/rollup.config.mjs @@ -0,0 +1,116 @@ +import alias from '@rollup/plugin-alias'; +import {babel} from '@rollup/plugin-babel'; +import commonjs from '@rollup/plugin-commonjs'; +import copy from 'rollup-plugin-copy'; +import {nodeResolve} from '@rollup/plugin-node-resolve'; +import terser from '@rollup/plugin-terser'; +import * as fse from 'fs-extra'; +import * as path from 'path'; +import css from 'rollup-plugin-css-only'; + +const BUILD = 'DEV'; +const SRC = path.resolve('src'); +const DST = SRC + '/dist'; +const DST_JS = DST + '/js'; +const ENTRY_BG = 'background'; +const ENTRIES = [ + 'edit', + ENTRY_BG, +]; + +const getChunkName = chunk => path.basename(chunk.facadeModuleId || '') || 'chunk.js'; + +const OUTPUT = { + dir: DST, + chunkFileNames: getChunkName, + entryFileNames: '[name].js', + generatedCode: 'es2015', + externalLiveBindings: false, + freeze: false, + // sourcemap: 'inline', +}; +const PLUGINS = [ + commonjs(), + nodeResolve(), + alias({ + entries: [ + {find: /^(?=\/)/, replacement: SRC}, + {find: './fs-drive', replacement: path.resolve('tools/shim/empty.js')}, + {find: 'fs', replacement: path.resolve('tools/shim/empty.js')}, + {find: 'path', replacement: path.resolve('tools/shim/path.js')}, + ], + }), + babel({ + babelHelpers: 'bundled', + presets: [ + ['@babel/preset-env', { + useBuiltIns: false, + bugfixes: true, + loose: true, + }], + ], + }), +]; +const PLUGIN_TERSER = BUILD !== 'DEV' && terser({ + compress: { + ecma: 8, + passes: 2, + reduce_funcs: false, + unsafe_arrows: true, + }, + output: { + ascii_only: false, + comments: false, + wrap_func_args: false, + }, +}); +const PLUGINS_CSS = [...PLUGINS, css()]; + +const makeEntry = (entry, file, output, opts) => { + const plugins = !entry || entry === ENTRY_BG ? PLUGINS : PLUGINS_CSS; + const entryPrefix = entry ? entry + '-' : ''; + return ({ + input: { + [entry || path.parse(file).name]: file || `${SRC}/${entry}/index.js`, + }, + output: { + ...OUTPUT, + dir: entry ? DST : DST_JS, + intro: entry ? `const __BUILD = "${BUILD}", __ENTRY = "${entry}";` : '', + assetFileNames: entry ? entry + '.css' : undefined, + chunkFileNames: chunk => entryPrefix + getChunkName(chunk), + ...output, + }, + plugins: !entry ? plugins : [ + ...plugins, + copy({targets: [{src: path.resolve(`${SRC}/${entry}.html`), dest: DST}]}), + ], + ...opts, + }); +}; + +const makeEntryIIFE = (file, opts) => makeEntry(undefined, file, {format: 'iife'}, opts); + +if (PLUGIN_TERSER) { + PLUGINS.push(PLUGIN_TERSER); + PLUGINS_CSS.push(PLUGIN_TERSER); +} + +fse.emptyDirSync(DST); +for (const e of [ + 'manifest.json', + 'css/icons.ttf', + ...ENTRIES.map(e => e + '.html'), +]) { + fse.copy(`${SRC}/${e}`, `${DST}/${path.basename(e)}`, { + overwrite: true, + preserveTimestamps: true, + }); +} + +export default [ + ...ENTRIES.map(e => makeEntry(e)), + makeEntryIIFE('/edit/editor-worker.js'), + makeEntryIIFE('/js/csslint/csslint.js', {external: './parserlib'}), + makeEntryIIFE('/js/csslint/parserlib.js'), +]; diff --git a/src/background.html b/src/background.html new file mode 100644 index 00000000000..659c0dc897f --- /dev/null +++ b/src/background.html @@ -0,0 +1 @@ + diff --git a/src/background/background-worker.js b/src/background/background-worker.js index cfbbe89a4cb..ed98cd555a2 100644 --- a/src/background/background-worker.js +++ b/src/background/background-worker.js @@ -1,26 +1,25 @@ -/* global createWorkerApi */// worker-util.js 'use strict'; /** @namespace BackgroundWorker */ createWorkerApi({ async compileUsercss(...args) { - require(['/js/usercss-compiler']); /* global compileUsercss */ + importScripts('/js/usercss-compiler'); /* global compileUsercss */ return compileUsercss(...args); }, nullifyInvalidVars(vars) { - require(['/js/meta-parser']); /* global metaParser */ + importScripts('/js/meta-parser'); /* global metaParser */ return metaParser.nullifyInvalidVars(vars); }, parseMozFormat(...args) { - require(['/js/moz-parser']); /* global extractSections */ + importScripts('/js/moz-parser'); /* global extractSections */ return extractSections(...args); }, parseUsercssMeta(text) { - require(['/js/meta-parser']); + importScripts('/js/meta-parser'); return metaParser.parse(text); }, }); diff --git a/src/background/bg-prefs.js b/src/background/bg-prefs.js index 1e3d8cb042e..584264ad772 100644 --- a/src/background/bg-prefs.js +++ b/src/background/bg-prefs.js @@ -1,40 +1,38 @@ -/* global addAPI bgReady */// common.js -/* global chromeSync */// storage-util.js -/* global debounce deepCopy deepEqual */ // toolbox.js -/* global prefs */ -'use strict'; +import * as prefs from '/js/prefs'; +import {chromeSync} from '/js/storage-util'; +import {debounce, deepCopy, deepEqual} from '/js/toolbox'; +import {addAPI, bgReady} from './common'; -(() => { - const nondefaults = {}; - const {__defaults, STORAGE_KEY, set} = prefs; - const updateStorage = () => chromeSync.setValue(STORAGE_KEY, nondefaults); +const nondefaults = {}; +const updateStorage = () => chromeSync.setValue(prefs.STORAGE_KEY, nondefaults); - addAPI(/** @namespace API */{ - prefs: { - /** @returns {Object} only the non-default preferences. - * WARNING for bg context: properties of object type are direct references into `values`! - * In non-bg contexts this is correctly deep-copied by msg.js::API. */ - get: () => nondefaults, - set: prefs.set = (key, val, ...rest) => { - if (set(key, val, ...rest)) { - const def = __defaults[key]; - if (val !== def && !(val && typeof def === 'object' && deepEqual(val, def))) { - nondefaults[key] = val; - } else if (key in nondefaults) { - delete nondefaults[key]; - } else { - return; - } - debounce(updateStorage); - return true; - } - }, - }, - }); +addAPI(/** @namespace API */{ + prefs: { + /** @returns {Object} only the non-default preferences. + * WARNING for bg context: properties of object type are direct references into `values`! + * In non-bg contexts this is correctly deep-copied by msg.js::API. */ + get: () => nondefaults, + set: bgPrefsSet, + }, +}); - chromeSync.getValue(STORAGE_KEY).then(orig => { - const copy = orig && typeof orig === 'object' ? deepCopy(orig) : {}; - prefs.ready.set(copy, {}); - if (!deepEqual(orig, nondefaults)) bgReady.all.then(updateStorage); - }); -})(); +chromeSync.getValue(prefs.STORAGE_KEY).then(orig => { + const copy = orig && typeof orig === 'object' ? deepCopy(orig) : {}; + prefs.ready.set(copy, {}); + if (!deepEqual(orig, nondefaults)) bgReady.all.then(updateStorage); +}); + +export function bgPrefsSet(key, val, ...rest) { + if (prefs.set(key, val, ...rest)) { + const def = prefs.__defaults[key]; + if (val !== def && !(val && typeof def === 'object' && deepEqual(val, def))) { + nondefaults[key] = val; + } else if (key in nondefaults) { + delete nondefaults[key]; + } else { + return; + } + debounce(updateStorage); + return true; + } +} diff --git a/src/background/broadcast-injector-config.js b/src/background/broadcast-injector-config.js new file mode 100644 index 00000000000..dfa80b2d9d2 --- /dev/null +++ b/src/background/broadcast-injector-config.js @@ -0,0 +1,36 @@ +import {broadcast} from './broadcast'; +import {getUrlOrigin} from './tab-util'; + +let cfg; +export const INJECTOR_CONFIG_MAP = { + exposeIframes: 'top', + disableAll: 'off', + styleViaASS: 'ass', +}; + +export default function broadcastInjectorConfig(key, val) { + if (!cfg) { + cfg = {}; + setTimeout(throttle); + } + cfg[INJECTOR_CONFIG_MAP[key] || key] = val; +} + +const data = { + method: 'injectorConfig', + cfg, +}; + +function setTop(tab) { + data.cfg.top = tab && getUrlOrigin(tab.url); + return data; +} + +function throttle() { + data.cfg = cfg; + broadcast(data, { + getData: cfg.top && setTop, + onlyIfStyled: !('off' in cfg || 'dark' in cfg), + }); + cfg = null; +} diff --git a/src/background/broadcast.js b/src/background/broadcast.js new file mode 100644 index 00000000000..f178d8f9621 --- /dev/null +++ b/src/background/broadcast.js @@ -0,0 +1,35 @@ +import browser from '/js/browser'; +import {sendTab, unwrap} from '/js/msg'; +import {URLS} from '/js/toolbox'; +import tabMan from './tab-manager'; + +/** + * @param {?} data + * @param {{}} [opts] + * @param {boolean} [opts.onlyIfStyled] - only tabs that are known to contain styles + * @param {(tab?:Tab)=>?} [opts.getData] - provides data for this tab, nullish result = skips tab + * @return {Promise} + */ +export async function broadcast(data, {onlyIfStyled, getData} = {}) { + const jobs = []; + if (!getData || (data = getData())) { + jobs.push(broadcastExtension(data, 'both')); + } + const tabs = (await browser.tabs.query({})).sort((a, b) => b.active - a.active); + for (const tab of tabs) { + if (!tab.discarded && + // including tabs with unsupported `url` as they may contain supported iframes + (!onlyIfStyled || tabMan.getStyleIds(tab.id)) && + // own tabs are informed via broadcastExtension + !(tab.pendingUrl || tab.url || '').startsWith(URLS.ownOrigin) && + (!getData || (data = getData(tab))) + ) { + jobs.push(sendTab(tab.id, data)); + } + } + return Promise.all(jobs); +} + +export function broadcastExtension(data, target = 'extension') { + return unwrap(browser.runtime.sendMessage({data, target})); +} diff --git a/src/background/browser-cmd-hotkeys.js b/src/background/browser-cmd-hotkeys.js index 3d2572ce6b4..d8e2c8f135c 100644 --- a/src/background/browser-cmd-hotkeys.js +++ b/src/background/browser-cmd-hotkeys.js @@ -1,20 +1,16 @@ -/* global prefs */ -'use strict'; +import browser from '/js/browser'; +import {knownKeys, subscribe} from '/js/prefs'; +import {FIREFOX} from '/js/toolbox'; -/* - Registers hotkeys in FF - */ - -(() => { - const hotkeyPrefs = prefs.knownKeys.filter(k => k.startsWith('hotkey.')); - prefs.subscribe(hotkeyPrefs, updateHotkey, true); - - async function updateHotkey(name, value) { +if (FIREFOX && ((browser.commands || {}).update)) { + subscribe(knownKeys.filter(k => k.startsWith('hotkey.')), async (name, value) => { try { - name = name.split('.')[1]; if (value.trim()) { - await browser.commands.update({name, shortcut: value}); + await browser.commands.update({ + name: name.split('.')[1], + shortcut: value, + }); } } catch (e) {} - } -})(); + }, true); +} diff --git a/src/background/color-scheme.js b/src/background/color-scheme.js index a8a63c24a68..11a671e9536 100644 --- a/src/background/color-scheme.js +++ b/src/background/color-scheme.js @@ -1,109 +1,106 @@ -/* global debounce */// toolbox.js -/* global prefs */ -/* exported colorScheme */ +import {debounce} from '/js/toolbox'; +import * as prefs from '/js/prefs'; -'use strict'; +const changeListeners = new Set(); +const kSTATE = 'schemeSwitcher.enabled'; +const kSTART = 'schemeSwitcher.nightStart'; +const kEND = 'schemeSwitcher.nightEnd'; +export const SCHEMES = ['dark', 'light']; +const mode = { + never: null, + dark: true, + light: false, + system: false, + time: false, +}; +let isDarkNow = false; +// matchMedia's onchange doesn't work in bg context, so we use it in our content script +update('system', matchMedia('(prefers-color-scheme:dark)').matches); +prefs.subscribe(kSTATE, (_, val) => { + if (val === 'time') { + prefs.subscribe([kSTART, kEND], onNightChanged, true); + chrome.alarms.onAlarm.addListener(onAlarm); + } else if (chrome.alarms.onAlarm.hasListener(onAlarm)) { + prefs.unsubscribe([kSTART, kEND], onNightChanged); + chrome.alarms.onAlarm.removeListener(onAlarm); + chrome.alarms.clear(kSTART); + chrome.alarms.clear(kEND); + } + update(); +}, true); -const colorScheme = (() => { - const changeListeners = new Set(); - const kSTATE = 'schemeSwitcher.enabled'; - const kSTART = 'schemeSwitcher.nightStart'; - const kEND = 'schemeSwitcher.nightEnd'; - const SCHEMES = ['dark', 'light']; - const isDark = { - never: null, - dark: true, - light: false, - system: false, - time: false, - }; - let isDarkNow = false; - // matchMedia's onchange doesn't work in bg context, so we use it in our content script - update('system', matchMedia('(prefers-color-scheme:dark)').matches); - prefs.subscribe(kSTATE, (_, val) => { - if (val === 'time') { - prefs.subscribe([kSTART, kEND], onNightChanged, true); - chrome.alarms.onAlarm.addListener(onAlarm); - } else if (chrome.alarms.onAlarm.hasListener(onAlarm)) { - prefs.unsubscribe([kSTART, kEND], onNightChanged); - chrome.alarms.onAlarm.removeListener(onAlarm); - chrome.alarms.clear(kSTART); - chrome.alarms.clear(kEND); - } - update(); - }, true); +export function onChange(listener, runNow) { + changeListeners.add(listener); + if (runNow) listener(isDarkNow); +} - return { - SCHEMES, - onChange(listener, runNow) { - changeListeners.add(listener); - if (runNow) listener(isDarkNow); - }, - isDark: () => isDarkNow, - /** @param {StyleObj} _ */ - shouldIncludeStyle({preferScheme: ps}) { - return prefs.get(kSTATE) === 'never' || - !SCHEMES.includes(ps) || - isDarkNow === (ps === 'dark'); - }, - setSystem(val) { - update('system', val); - }, - }; +export function isDark() { + return isDarkNow; +} - function calcTime(key) { - const [h, m] = prefs.get(key).split(':'); - return (h * 3600 + m * 60) * 1000; - } +/** @param {StyleObj} _ */ +export function shouldIncludeStyle({preferScheme: ps}) { + return prefs.get(kSTATE) === 'never' || + !SCHEMES.includes(ps) || + isDarkNow === (ps === 'dark'); +} - function createAlarm(key, value) { - const date = new Date(); - const [h, m] = value.split(':'); - date.setHours(h, m, 0, 0); - if (date.getTime() < Date.now()) { - date.setDate(date.getDate() + 1); - } - chrome.alarms.create(key, { - when: date.getTime(), - periodInMinutes: 24 * 60, - }); - } +export function setSystem(val) { + update('system', val); +} - function onAlarm({name}) { - if (name === kSTART || name === kEND) { - updateTimePreferDark(); - } +function calcTime(key) { + const [h, m] = prefs.get(key).split(':'); + return (h * 3600 + m * 60) * 1000; +} + +function createAlarm(key, value) { + const date = new Date(); + const [h, m] = value.split(':'); + date.setHours(h, m, 0, 0); + if (date.getTime() < Date.now()) { + date.setDate(date.getDate() + 1); } + chrome.alarms.create(key, { + when: date.getTime(), + periodInMinutes: 24 * 60, + }); +} - function onNightChanged(force) { - if (force !== true) return debounce(onNightChanged, 0, true); +function onAlarm({name}) { + if (name === kSTART || name === kEND) { updateTimePreferDark(); - // recreating both alarms as the user may have been in a different timezone when setting the other one - createAlarm(kSTART, prefs.get(kSTART)); - createAlarm(kEND, prefs.get(kEND)); } +} - function updateTimePreferDark() { - const now = Date.now() - new Date().setHours(0, 0, 0, 0); - const start = calcTime(kSTART); - const end = calcTime(kEND); - const val = start > end ? - now >= start || now < end : - now >= start && now < end; - update('time', val); - } +function onNightChanged(force) { + if (force !== true) return debounce(onNightChanged, 0, true); + updateTimePreferDark(); + // recreating both alarms as the user may have been in a different timezone when setting the other one + createAlarm(kSTART, prefs.get(kSTART)); + createAlarm(kEND, prefs.get(kEND)); +} - function update(type, val) { - if (type) { - if (isDark[type] === val) return; - isDark[type] = val; - } - val = isDark[prefs.get(kSTATE)]; - if (isDarkNow !== val) { - isDarkNow = val; - for (const listener of changeListeners) { - listener(isDarkNow); - } +function updateTimePreferDark() { + const now = Date.now() - new Date().setHours(0, 0, 0, 0); + const start = calcTime(kSTART); + const end = calcTime(kEND); + const val = start > end ? + now >= start || now < end : + now >= start && now < end; + update('time', val); +} + +function update(type, val) { + if (type) { + if (mode[type] === val) return; + mode[type] = val; + } + val = mode[prefs.get(kSTATE)]; + if (isDarkNow !== val) { + isDarkNow = val; + for (const listener of changeListeners) { + listener(isDarkNow); } } -})(); +} diff --git a/src/background/common.js b/src/background/common.js index 843fa216ff8..9d8b4c306b7 100644 --- a/src/background/common.js +++ b/src/background/common.js @@ -1,53 +1,14 @@ -/* global URLS tryJSONparse */// toolbox.js -/* global tabMan */// tab-manager.js -/* global getUrlOrigin */// tab-util.js -'use strict'; +import browser from '/js/browser'; -/** - * Common stuff that's loaded first so it's immediately available to all background scripts - */ - -window.bgReady = {}; /* global bgReady */ +export const bgReady = self.bgReady = {}; bgReady.styles = new Promise(r => (bgReady._resolveStyles = r)); bgReady.all = new Promise(r => (bgReady._resolveAll = r)); -const API = window.API = { - download, -}; +export const API = {}; -const msg = window.msg = /** @namespace msg */ { - bg: window, - /** - * @param {?} data - * @param {{}} [opts] - * @param {boolean} [opts.onlyIfStyled] - only tabs that are known to contain styles - * @param {(tab?:Tab)=>?} [opts.getData] - provides data for this tab, nullish result = skips tab - * @return {Promise} - */ - async broadcast(data, {onlyIfStyled, getData} = {}) { - const jobs = []; - if (!getData || (data = getData())) { - jobs.push(this.broadcastExtension(data, 'both')); - } - const tabs = (await browser.tabs.query({})).sort((a, b) => b.active - a.active); - for (const tab of tabs) { - if (!tab.discarded && - // including tabs with unsupported `url` as they may contain supported iframes - (!onlyIfStyled || tabMan.getStyleIds(tab.id)) && - // own tabs are informed via broadcastExtension - !(tab.pendingUrl || tab.url || '').startsWith(URLS.ownOrigin) && - (!getData || (data = getData(tab))) - ) { - jobs.push(msg.sendTab(tab.id, data)); - } - } - return Promise.all(jobs); - }, - broadcastExtension(data, target = 'extension') { - return msg._unwrap(browser.runtime.sendMessage({data, target})); - }, -}; -const uuidIndex = Object.assign(new Map(), { +export const browserCommands = {}; + +export const uuidIndex = Object.assign(new Map(), { custom: {}, /** `obj` must have a unique `id`, a UUIDv4 `_id`, and Date.now() for `_rev`. */ addCustom(obj, {get = () => obj, set}) { @@ -55,8 +16,9 @@ const uuidIndex = Object.assign(new Map(), { }, }); -/* exported addAPI */ -function addAPI(methods) { +export let isVivaldi = chrome.app ? null : false; + +export function addAPI(methods) { for (const [key, val] of Object.entries(methods)) { const old = API[key]; if (old && Object.prototype.toString.call(old) === '[object Object]') { @@ -67,236 +29,7 @@ function addAPI(methods) { } } -/* exported broadcastInjectorConfig */ -const broadcastInjectorConfig = (( - cfg, - map = { - exposeIframes: 'top', - disableAll: 'off', - styleViaASS: 'ass', - }, - data = { - method: 'injectorConfig', - cfg, - } -) => { - return run; - function setTop(tab) { - data.cfg.top = tab && getUrlOrigin(tab.url); - return data; - } - function throttle() { - data.cfg = cfg; - msg.broadcast(data, { - getData: cfg.top && setTop, - onlyIfStyled: !('off' in cfg || 'dark' in cfg), - }); - cfg = null; - } - function run(key, val) { - if (!cfg) { - cfg = {}; - setTimeout(throttle); - } - cfg[map[key] || key] = val; - } -})(); - -/* exported createCache */ -/** Creates a FIFO limit-size map. */ -function createCache({size = 1000, onDeleted} = {}) { - const map = new Map(); - const buffer = Array(size); - let index = 0; - let lastIndex = 0; - return { - get(id) { - const item = map.get(id); - return item && item.data; - }, - set(id, data) { - if (map.size === size) { - // full - map.delete(buffer[lastIndex].id); - if (onDeleted) { - onDeleted(buffer[lastIndex].id, buffer[lastIndex].data); - } - lastIndex = (lastIndex + 1) % size; - } - const item = {id, data, index}; - map.set(id, item); - buffer[index] = item; - index = (index + 1) % size; - }, - delete(id) { - const item = map.get(id); - if (!item) { - return false; - } - map.delete(item.id); - const lastItem = buffer[lastIndex]; - lastItem.index = item.index; - buffer[item.index] = lastItem; - lastIndex = (lastIndex + 1) % size; - if (onDeleted) { - onDeleted(item.id, item.data); - } - return true; - }, - clear() { - map.clear(); - index = lastIndex = 0; - }, - has: id => map.has(id), - *entries() { - for (const [id, item] of map) { - yield [id, item.data]; - } - }, - *values() { - for (const item of map.values()) { - yield item.data; - } - }, - get size() { - return map.size; - }, - }; -} - -/* exported isVivaldi */ -let isVivaldi = chrome.app ? null : false; -/* exported detectVivaldi */ -async function detectVivaldi() { +export async function detectVivaldi() { const wnd = await browser.windows.getCurrent(); return (isVivaldi = wnd && !!(wnd.vivExtData || wnd.extData)); } - -const downloadRequests = {}; -/* exported download */ -/** - * @param {String} url - * @param {Object} params - * @param {String} [params.method] - * @param {String|Object} [params.body] - * @param {'arraybuffer'|'blob'|'document'|'json'|'text'} [params.responseType] - * @param {Number} [params.requiredStatusCode] resolved when matches, otherwise rejected - * @param {Number} [params.timeout] ms - * @param {Object} [params.headers] {name: value} - * @param {string[]} [params.responseHeaders] - * @param {string} [params.port] messaging port's name to receive onprogress reports - * @returns {Promise} - */ -function download(url, { - method = 'GET', - body, - responseType = 'text', - requiredStatusCode = 200, - timeout = 60e3, // connection timeout, USO is that bad - loadTimeout = 2 * 60e3, // data transfer timeout (counted from the first remote response) - headers, - responseHeaders, - port, -} = {}) { - let xhr; - /* USO can't handle POST requests for style json and XHR/fetch can't handle super long URL - * so we need to collapse all long variables and expand them in the response */ - const queryPos = url.startsWith(URLS.uso) ? url.indexOf('?') : -1; - if (queryPos >= 0) { - if (body === undefined) { - method = 'POST'; - body = url.slice(queryPos); - url = url.slice(0, queryPos); - } - if (headers === undefined) { - headers = { - 'Content-type': 'application/x-www-form-urlencoded', - }; - } - } - const usoVars = []; - const reqKey = arguments[1] ? JSON.stringify(arguments) : url; - const req = downloadRequests[reqKey] || (downloadRequests[reqKey] = new Promise((resolve, reject) => { - xhr = new XMLHttpRequest(); - const u = new URL(collapseUsoVars(url), location); - const onTimeout = () => { - xhr.abort(); - reject(new Error('Timeout fetching ' + u.href)); - }; - let timer = setTimeout(onTimeout, timeout); - xhr.onreadystatechange = () => { - if (xhr.readyState >= XMLHttpRequest.HEADERS_RECEIVED) { - xhr.onreadystatechange = null; - clearTimeout(timer); - timer = loadTimeout && setTimeout(onTimeout, loadTimeout); - } - }; - xhr.onload = () => { - if (xhr.status === requiredStatusCode || !requiredStatusCode || u.protocol === 'file:') { - const response = expandUsoVars(xhr.response); - if (responseHeaders) { - const headers = {}; - for (const h of responseHeaders) headers[h] = xhr.getResponseHeader(h); - resolve({headers, response}); - } else { - resolve(response); - } - } else { - reject(xhr.status); - } - }; - xhr.onerror = () => reject(xhr.status); - xhr.onloadend = () => { - clearTimeout(timer); - delete downloadRequests[reqKey]; - }; - xhr.responseType = responseType; - xhr.open(method, u.href); - for (const [name, value] of Object.entries(headers || {})) { - xhr.setRequestHeader(name, value); - } - xhr.send(body); - })); - if (xhr) req.xhr = xhr; - if (port) { - const ports = req.ports || ( - req.xhr.onprogress = e => ports.forEach(p => p.postMessage([e.loaded, e.total])), - req.xhr.addEventListener('loadend', () => ports.forEach(p => p.disconnect())), - new Set() - ); - const p = chrome.runtime.connect({name: port}); - p.onDisconnect.addListener(() => ports.delete(p)); - ports.add(p); - } - return req; - - function collapseUsoVars(url) { - if (queryPos < 0 || - url.length < 2000 || - !url.startsWith(URLS.usoJson) || - !/^get$/i.test(method)) { - return url; - } - const params = new URLSearchParams(url.slice(queryPos + 1)); - for (const [k, v] of params.entries()) { - if (v.length < 10 || v.startsWith('ik-')) continue; - usoVars.push(v); - params.set(k, `\x01${usoVars.length}\x02`); - } - return url.slice(0, queryPos + 1) + params.toString(); - } - - function expandUsoVars(response) { - if (!usoVars.length || !response) return response; - const isText = typeof response === 'string'; - const json = isText && tryJSONparse(response) || response; - json.updateUrl = url; - for (const section of json.sections || []) { - const {code} = section; - if (code.includes('\x01')) { - section.code = code.replace(/\x01(\d+)\x02/g, (_, num) => usoVars[num - 1] || ''); - } - } - return isText ? JSON.stringify(json) : json; - } -} diff --git a/src/background/content-scripts.js b/src/background/content-scripts.js index f0eef1b5b91..61dd8b1fe49 100644 --- a/src/background/content-scripts.js +++ b/src/background/content-scripts.js @@ -1,15 +1,15 @@ -/* global bgReady */// common.js -/* global msg */ -/* global tabMan */ -/* global URLS ignoreChromeError stringAsRegExpStr */// toolbox.js -'use strict'; +import browser from '/js/browser'; +import {sendTab} from '/js/msg'; +import {ignoreChromeError, stringAsRegExpStr, URLS} from '/js/toolbox'; +import {bgReady} from './common'; +import tabMan from './tab-manager'; -/* +/** Reinject content scripts when the extension is reloaded/updated. Not used in Firefox as it reinjects automatically. */ -bgReady.all.then(() => { +if (CHROME) bgReady.all.then(() => { // eslint-disable-line curly const ALL_URLS = ''; const SCRIPTS = chrome.runtime.getManifest().content_scripts; const globToRe = (s, re = '.') => stringAsRegExpStr(s.replace(/\*/g, '\n')).replace(/\n/g, re + '*?'); @@ -30,7 +30,7 @@ bgReady.all.then(() => { async function injectToTab(tabId, url) { const jobs = []; tabMan.set(tabId, 'url', url); - if (await msg.sendTab(tabId, {method: 'backgroundReady'})) { + if (await sendTab(tabId, {method: 'backgroundReady'})) { return; } for (const cs of SCRIPTS) { diff --git a/src/background/context-menus.js b/src/background/context-menus.js index dddefb0c216..59d7af36e10 100644 --- a/src/background/context-menus.js +++ b/src/background/context-menus.js @@ -1,8 +1,9 @@ -/* global browserCommands */// background.js -/* global msg */ -/* global prefs */ -/* global CHROME URLS ignoreChromeError */// toolbox.js -'use strict'; +import browser from '/js/browser'; +import {sendTab} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {CHROME, URLS, ignoreChromeError} from '/js/toolbox'; +import {browserCommands} from './common'; +import {bgPrefsSet} from './bg-prefs'; chrome.management.getSelf(ext => { const contextMenus = Object.assign({ @@ -34,7 +35,7 @@ chrome.management.getSelf(ext => { contexts: ['editable'], documentUrlPatterns: [URLS.ownOrigin + '*'], click: (info, tab) => { - msg.sendTab(tab.id, {method: 'editDeleteText'}, undefined, 'extension'); + sendTab(tab.id, {method: 'editDeleteText'}, undefined, 'extension'); }, }, }); @@ -51,7 +52,11 @@ chrome.management.getSelf(ext => { if (!item.type) { item.type = 'checkbox'; item.checked = prefs.get(id); - if (isInit) prefs.subscribe(id, CHROME >= 62 && CHROME <= 64 ? toggleCheckmarkBugged : toggleCheckmark); + if (isInit) { + prefs.subscribe(id, CHROME >= 62 && CHROME <= 64 + ? toggleCheckmarkBugged + : toggleCheckmark); + } } else if (isInit) { prefs.subscribe(id, togglePresence, true); continue; @@ -74,7 +79,7 @@ chrome.management.getSelf(ext => { /** @param {chrome.contextMenus.OnClickData} info */ function togglePref(info) { - prefs.set(info.menuItemId, info.checked); + bgPrefsSet(info.menuItemId, info.checked); } function togglePresence(id, checked) { diff --git a/src/background/db-chrome-storage.js b/src/background/db-chrome-storage.js index 416e9c095db..85db39a507a 100644 --- a/src/background/db-chrome-storage.js +++ b/src/background/db-chrome-storage.js @@ -1,8 +1,6 @@ -/* global chromeLocal */// storage-util.js -'use strict'; +import {chromeLocal} from '/js/storage-util'; -/* exported createChromeStorageDB */ -function createChromeStorageDB(PREFIX) { +export default function ChromeStorageDB(PREFIX) { let INC; const isMain = !PREFIX; if (!PREFIX) PREFIX = 'style-'; diff --git a/src/background/db.js b/src/background/db.js index 97ceff09eca..40d25c4b865 100644 --- a/src/background/db.js +++ b/src/background/db.js @@ -1,9 +1,8 @@ -/* global addAPI */// common.js -/* global chromeLocal */// storage-util.js -/* global cloneError */// worker-util.js -/* global deepCopy */// toolbox.js -/* global prefs */ -'use strict'; +import {STORAGE_KEY} from '/js/prefs'; +import {chromeLocal} from '/js/storage-util'; +import {deepCopy} from '/js/toolbox'; +import {addAPI} from './common'; +import ChromeStorageDB from './db-chrome-storage'; /* Initialize a database. There are some problems using IndexedDB in Firefox: @@ -12,139 +11,138 @@ https://www.reddit.com/r/firefox/comments/7ijuaq/firefox_59_webextensions_can_use_indexeddb_when/ */ -/* exported db */ -const db = (() => { - let exec = async (...args) => ( - exec = await tryUsingIndexedDB().catch(useChromeStorage) - )(...args); - const DB = 'stylish'; - const FALLBACK = 'dbInChromeStorage'; - const ID_AS_KEY = {[DB]: true}; - const getStoreName = dbName => dbName === DB ? 'styles' : 'data'; - const cache = {}; - const proxies = {}; - const proxyHandler = { - get: ({dbName}, cmd) => - (...args) => - (dbName === DB ? exec : cachedExec)(dbName, cmd, ...args), - }; - /** - * @param {string} dbName - * @return {IDBObjectStore | {putMany: function(items:?[]):Promise}} - */ - const getProxy = dbName => proxies[dbName] || ( - (proxies[dbName] = new Proxy({dbName}, proxyHandler)) - ); - addAPI(/** @namespace API */ { - drafts: getProxy('drafts'), - /** Storage for big items that may exceed 8kB limit of chrome.storage.sync. - * To make an item syncable register it with uuidIndex.addCustom. */ - prefsDb: getProxy(prefs.STORAGE_KEY), - }); - return { - styles: getProxy(DB), - }; +let exec = async (...args) => ( + exec = await tryUsingIndexedDB().catch(useChromeStorage) +)(...args); +const DB = 'stylish'; +const FALLBACK = 'dbInChromeStorage'; +const ID_AS_KEY = {[DB]: true}; +const getStoreName = dbName => dbName === DB ? 'styles' : 'data'; +const cache = {}; +const proxies = {}; +const proxyHandler = { + get: ({dbName}, cmd) => + (...args) => + (dbName === DB ? exec : cachedExec)(dbName, cmd, ...args), +}; +/** + * @param {string} dbName + * @return {IDBObjectStore | {putMany: function(items:?[]):Promise}} + */ +const getProxy = dbName => proxies[dbName] || ( + (proxies[dbName] = new Proxy({dbName}, proxyHandler)) +); +const db = { + styles: getProxy(DB), +}; - async function cachedExec(dbName, cmd, a, b) { - const hub = cache[dbName] || (cache[dbName] = {}); - const res = cmd === 'get' && a in hub ? hub[a] : await exec(...arguments); - if (cmd === 'get') { - hub[a] = deepCopy(res); - } else if (cmd === 'put') { - hub[ID_AS_KEY[dbName] ? a.id : b] = deepCopy(a); - } else if (cmd === 'delete') { - delete hub[a]; - } - return res; - } +addAPI(/** @namespace API */ { + drafts: getProxy('drafts'), + /** Storage for big items that may exceed 8kB limit of chrome.storage.sync. + * To make an item syncable register it with uuidIndex.addCustom. */ + prefsDb: getProxy(STORAGE_KEY), +}); - async function tryUsingIndexedDB() { - // we use chrome.storage.local fallback if IndexedDB doesn't save data, - // which, once detected on the first run, is remembered in chrome.storage.local - // note that accessing indexedDB may throw, https://github.com/openstyles/stylus/issues/615 - if (typeof indexedDB === 'undefined') { - throw new Error('indexedDB is undefined'); - } - switch (await chromeLocal.getValue(FALLBACK)) { - case true: throw null; - case false: break; - default: await testDB(); - } - chromeLocal.setValue(FALLBACK, false); - return dbExecIndexedDB; +async function cachedExec(dbName, cmd, a, b) { + const hub = cache[dbName] || (cache[dbName] = {}); + const res = cmd === 'get' && a in hub ? hub[a] : await exec(...arguments); + if (cmd === 'get') { + hub[a] = deepCopy(res); + } else if (cmd === 'put') { + hub[ID_AS_KEY[dbName] ? a.id : b] = deepCopy(a); + } else if (cmd === 'delete') { + delete hub[a]; } + return res; +} - async function testDB() { - const id = `${performance.now()}.${Math.random()}.${Date.now()}`; - await dbExecIndexedDB(DB, 'put', {id}); - const e = await dbExecIndexedDB(DB, 'get', id); - await dbExecIndexedDB(DB, 'delete', e.id); // throws if `e` or id is null +async function tryUsingIndexedDB() { + // we use chrome.storage.local fallback if IndexedDB doesn't save data, + // which, once detected on the first run, is remembered in chrome.storage.local + // note that accessing indexedDB may throw, https://github.com/openstyles/stylus/issues/615 + if (typeof indexedDB === 'undefined') { + throw new Error('indexedDB is undefined'); } - - async function useChromeStorage(err) { - chromeLocal.setValue(FALLBACK, true); - if (err) { - chromeLocal.setValue(FALLBACK + 'Reason', cloneError(err)); - console.warn('Failed to access indexedDB. Switched to storage API.', err); - } - await require(['/background/db-chrome-storage']); /* global createChromeStorageDB */ - const BASES = {}; - return (dbName, method, ...args) => ( - BASES[dbName] || ( - BASES[dbName] = createChromeStorageDB(dbName !== DB && `${dbName}-`) - ) - )[method](...args); + switch (await chromeLocal.getValue(FALLBACK)) { + case true: throw null; + case false: break; + default: await testDB(); } + chromeLocal.setValue(FALLBACK, false); + return dbExecIndexedDB; +} - async function dbExecIndexedDB(dbName, method, ...args) { - const mode = method.startsWith('get') ? 'readonly' : 'readwrite'; - const storeName = getStoreName(dbName); - const store = (await open(dbName)).transaction([storeName], mode).objectStore(storeName); - const fn = method === 'putMany' ? putMany : storeRequest; - return fn(store, method, ...args); - } +async function testDB() { + const id = `${performance.now()}.${Math.random()}.${Date.now()}`; + await dbExecIndexedDB(DB, 'put', {id}); + const e = await dbExecIndexedDB(DB, 'get', id); + await dbExecIndexedDB(DB, 'delete', e.id); // throws if `e` or id is null +} - function storeRequest(store, method, ...args) { - return new Promise((resolve, reject) => { - /** @type {IDBRequest} */ - const request = store[method](...args); - request.onsuccess = () => resolve(request.result); - request.onerror = reject; - }); +async function useChromeStorage(err) { + chromeLocal.setValue(FALLBACK, true); + if (err) { + chromeLocal.setValue(FALLBACK + 'Reason', err.message + (err.stack ? '\n' + err.stack : '')); + console.warn('Failed to access indexedDB. Switched to storage API.', err); } + const BASES = {}; + return (dbName, method, ...args) => ( + BASES[dbName] || ( + BASES[dbName] = ChromeStorageDB(dbName !== DB && `${dbName}-`) + ) + )[method](...args); +} - function putMany(store, _method, items) { - return Promise.all(items.map(item => storeRequest(store, 'put', item))); - } +async function dbExecIndexedDB(dbName, method, ...args) { + const mode = method.startsWith('get') ? 'readonly' : 'readwrite'; + const storeName = getStoreName(dbName); + const store = (await open(dbName)).transaction([storeName], mode).objectStore(storeName); + const fn = method === 'putMany' ? putMany : storeRequest; + return fn(store, method, ...args); +} - function open(name) { - return new Promise((resolve, reject) => { - const request = indexedDB.open(name, 2); - request.onsuccess = e => resolve(create(e)); - request.onerror = reject; - request.onupgradeneeded = create; - }); - } +function storeRequest(store, method, ...args) { + return new Promise((resolve, reject) => { + /** @type {IDBRequest} */ + const request = store[method](...args); + request.onsuccess = () => resolve(request.result); + request.onerror = reject; + }); +} + +function putMany(store, _method, items) { + return Promise.all(items.map(item => storeRequest(store, 'put', item))); +} - function create(event) { - /** @type IDBDatabase */ - const idb = event.target.result; - const dbName = idb.name; - const sn = getStoreName(dbName); - if (!idb.objectStoreNames.contains(sn)) { - if (event.type === 'success') { - idb.close(); - return new Promise(resolve => { - indexedDB.deleteDatabase(dbName).onsuccess = () => { - resolve(open(dbName)); - }; - }); - } - idb.createObjectStore(sn, ID_AS_KEY[dbName] ? { - keyPath: 'id', - autoIncrement: true, - } : undefined); +function open(name) { + return new Promise((resolve, reject) => { + const request = indexedDB.open(name, 2); + request.onsuccess = e => resolve(create(e)); + request.onerror = reject; + request.onupgradeneeded = create; + }); +} + +function create(event) { + /** @type IDBDatabase */ + const idb = event.target.result; + const dbName = idb.name; + const sn = getStoreName(dbName); + if (!idb.objectStoreNames.contains(sn)) { + if (event.type === 'success') { + idb.close(); + return new Promise(resolve => { + indexedDB.deleteDatabase(dbName).onsuccess = () => { + resolve(open(dbName)); + }; + }); } - return idb; + idb.createObjectStore(sn, ID_AS_KEY[dbName] ? { + keyPath: 'id', + autoIncrement: true, + } : undefined); } -})(); + return idb; +} + +export default db; diff --git a/src/background/download.js b/src/background/download.js new file mode 100644 index 00000000000..9f83cace8bb --- /dev/null +++ b/src/background/download.js @@ -0,0 +1,131 @@ +import {tryJSONparse, URLS} from '/js/toolbox'; + +const downloadRequests = {}; + +/** + * @param {String} url + * @param {Object} params + * @param {String} [params.method] + * @param {String|Object} [params.body] + * @param {'arraybuffer'|'blob'|'document'|'json'|'text'} [params.responseType] + * @param {Number} [params.requiredStatusCode] resolved when matches, otherwise rejected + * @param {Number} [params.timeout] ms + * @param {Object} [params.headers] {name: value} + * @param {string[]} [params.responseHeaders] + * @param {string} [params.port] messaging port's name to receive onprogress reports + * @returns {Promise} + */ +export default function download(url, { + method = 'GET', + body, + responseType = 'text', + requiredStatusCode = 200, + timeout = 60e3, // connection timeout, USO is that bad + loadTimeout = 2 * 60e3, // data transfer timeout (counted from the first remote response) + headers, + responseHeaders, + port, +} = {}) { + let xhr; + /* USO can't handle POST requests for style json and XHR/fetch can't handle super long URL + * so we need to collapse all long variables and expand them in the response */ + const queryPos = url.startsWith(URLS.uso) ? url.indexOf('?') : -1; + if (queryPos >= 0) { + if (body === undefined) { + method = 'POST'; + body = url.slice(queryPos); + url = url.slice(0, queryPos); + } + if (headers === undefined) { + headers = { + 'Content-type': 'application/x-www-form-urlencoded', + }; + } + } + const usoVars = []; + const reqKey = arguments[1] ? JSON.stringify(arguments) : url; + const req = downloadRequests[reqKey] + || (downloadRequests[reqKey] = new Promise((resolve, reject) => { + xhr = new XMLHttpRequest(); + const u = new URL(collapseUsoVars(url), location); + const onTimeout = () => { + xhr.abort(); + reject(new Error('Timeout fetching ' + u.href)); + }; + let timer = setTimeout(onTimeout, timeout); + xhr.onreadystatechange = () => { + if (xhr.readyState >= XMLHttpRequest.HEADERS_RECEIVED) { + xhr.onreadystatechange = null; + clearTimeout(timer); + timer = loadTimeout && setTimeout(onTimeout, loadTimeout); + } + }; + xhr.onload = () => { + if (xhr.status === requiredStatusCode || !requiredStatusCode || u.protocol === 'file:') { + const response = expandUsoVars(xhr.response); + if (responseHeaders) { + const headers = {}; + for (const h of responseHeaders) headers[h] = xhr.getResponseHeader(h); + resolve({headers, response}); + } else { + resolve(response); + } + } else { + reject(xhr.status); + } + }; + xhr.onerror = () => reject(xhr.status); + xhr.onloadend = () => { + clearTimeout(timer); + delete downloadRequests[reqKey]; + }; + xhr.responseType = responseType; + xhr.open(method, u.href); + for (const [name, value] of Object.entries(headers || {})) { + xhr.setRequestHeader(name, value); + } + xhr.send(body); + })); + if (xhr) req.xhr = xhr; + if (port) { + const ports = req.ports || ( + req.xhr.onprogress = e => ports.forEach(p => p.postMessage([e.loaded, e.total])), + req.xhr.addEventListener('loadend', () => ports.forEach(p => p.disconnect())), + new Set() + ); + const p = chrome.runtime.connect({name: port}); + p.onDisconnect.addListener(() => ports.delete(p)); + ports.add(p); + } + return req; + + function collapseUsoVars(url) { + if (queryPos < 0 || + url.length < 2000 || + !url.startsWith(URLS.usoJson) || + !/^get$/i.test(method)) { + return url; + } + const params = new URLSearchParams(url.slice(queryPos + 1)); + for (const [k, v] of params.entries()) { + if (v.length < 10 || v.startsWith('ik-')) continue; + usoVars.push(v); + params.set(k, `\x01${usoVars.length}\x02`); + } + return url.slice(0, queryPos + 1) + params.toString(); + } + + function expandUsoVars(response) { + if (!usoVars.length || !response) return response; + const isText = typeof response === 'string'; + const json = isText && tryJSONparse(response) || response; + json.updateUrl = url; + for (const section of json.sections || []) { + const {code} = section; + if (code.includes('\x01')) { + section.code = code.replace(/\x01(\d+)\x02/g, (_, num) => usoVars[num - 1] || ''); + } + } + return isText ? JSON.stringify(json) : json; + } +} diff --git a/src/background/icon-manager.js b/src/background/icon-manager.js index 2aaa42c25f0..4fad968a907 100644 --- a/src/background/icon-manager.js +++ b/src/background/icon-manager.js @@ -1,240 +1,233 @@ -/* global API */// msg.js -/* global addAPI bgReady */// common.js -/* global colorScheme */ -/* global prefs */ -/* global tabMan */ -/* global CHROME FIREFOX UA debounce ignoreChromeError */// toolbox.js -'use strict'; - -/* exported iconMan */ -const iconMan = (() => { - const ICON_SIZES = FIREFOX || CHROME && !UA.vivaldi ? [16, 32] : [19, 38]; - const staleBadges = new Set(); - const imageDataCache = new Map(); - const badgeOvr = {color: '', text: ''}; - // https://github.com/openstyles/stylus/issues/1287 Fenix can't use custom ImageData - const FIREFOX_ANDROID = FIREFOX && UA.mobile; - let isDark; - // https://github.com/openstyles/stylus/issues/335 - let hasCanvas = FIREFOX_ANDROID ? false : loadImage(`/images/icon/${ICON_SIZES[0]}.png`) - .then(({data}) => (hasCanvas = data.some(b => b !== 255))); - - addAPI(/** @namespace API */ { - /** - * @param {(number|string)[]} styleIds - * @param {{}} opts - * @param {boolean} [opts.lazyBadge=false] preventing flicker during page load - * @param {string} [opts.iid] - instance id - */ - updateIconBadge(styleIds, {lazyBadge, iid} = {}) { - // FIXME: in some cases, we only have to redraw the badge. is it worth a optimization? - const {tab: {id: tabId}, TDM} = this.sender; - const frameId = TDM > 0 ? 0 : this.sender.frameId; - const value = styleIds.length ? styleIds.map(Number) : undefined; - tabMan.set(tabId, 'styleIds', frameId, value); - if (iid) tabMan.set(tabId, 'iid', frameId, iid); - debounce(refreshStaleBadges, frameId && lazyBadge ? 250 : 0); - staleBadges.add(tabId); - if (!frameId) refreshIcon(tabId, true); - }, - }); - - chrome.webNavigation.onCommitted.addListener(({tabId, frameId}) => { - const ids = tabMan.getStyleIds(tabId); - if (!ids) return; - if (frameId) delete ids[frameId]; - else for (const id in ids) delete ids[id]; - }); - chrome.runtime.onConnect.addListener(port => { - if (port.name === 'iframe') { - port.onDisconnect.addListener(onPortDisconnected); +import * as prefs from '/js/prefs'; +import {debounce, FIREFOX, ignoreChromeError, UA} from '/js/toolbox'; +import * as colorScheme from './color-scheme'; +import {addAPI, API, bgReady} from './common'; +import tabMan from './tab-manager'; + +const ICON_SIZES = FIREFOX || !UA.vivaldi ? [16, 32] : [19, 38]; +const staleBadges = new Set(); +const imageDataCache = new Map(); +const badgeOvr = {color: '', text: ''}; +// https://github.com/openstyles/stylus/issues/1287 Fenix can't use custom ImageData +const FIREFOX_ANDROID = FIREFOX && UA.mobile; +let isDark; +// https://github.com/openstyles/stylus/issues/335 +let hasCanvas = FIREFOX_ANDROID ? false : loadImage(`/images/icon/${ICON_SIZES[0]}.png`) + .then(({data}) => (hasCanvas = data.some(b => b !== 255))); + +addAPI(/** @namespace API */ { +/** + * @param {(number|string)[]} styleIds + * @param {{}} opts + * @param {boolean} [opts.lazyBadge=false] preventing flicker during page load + * @param {string} [opts.iid] - instance id + */ + updateIconBadge(styleIds, {lazyBadge, iid} = {}) { + // FIXME: in some cases, we only have to redraw the badge. is it worth a optimization? + const {tab: {id: tabId}, TDM} = this.sender; + const frameId = TDM > 0 ? 0 : this.sender.frameId; + const value = styleIds.length ? styleIds.map(Number) : undefined; + tabMan.set(tabId, 'styleIds', frameId, value); + if (iid) tabMan.set(tabId, 'iid', frameId, iid); + debounce(refreshStaleBadges, frameId && lazyBadge ? 250 : 0); + staleBadges.add(tabId); + if (!frameId) refreshIcon(tabId, true); + }, +}); + +chrome.webNavigation.onCommitted.addListener(({tabId, frameId}) => { + const ids = tabMan.getStyleIds(tabId); + if (!ids) return; + if (frameId) delete ids[frameId]; + else for (const id in ids) delete ids[id]; +}); +chrome.runtime.onConnect.addListener(port => { + if (port.name === 'iframe') { + port.onDisconnect.addListener(onPortDisconnected); + } +}); +colorScheme.onChange(val => { + isDark = val; + if (prefs.get('iconset') === -1) { + debounce(refreshAllIcons); + } +}, true); +bgReady.all.then(() => { + prefs.subscribe([ + 'disableAll', + 'badgeDisabled', + 'badgeNormal', + ], () => debounce(refreshIconBadgeColor), true); + prefs.subscribe([ + 'show-badge', + ], () => debounce(refreshAllIconsBadgeText), true); + prefs.subscribe([ + 'disableAll', + 'iconset', + ], () => debounce(refreshAllIcons), true); +}); + + /** Calling with no params clears the override */ +export function overrideBadge({text = '', color = '', title = ''} = {}) { + if (badgeOvr.text === text) { + return; + } + badgeOvr.text = text; + badgeOvr.color = color; + refreshIconBadgeColor(); + setBadgeText({text}); + for (const tabId of tabMan.keys()) { + if (text) { + setBadgeText({tabId, text}); + } else { + refreshIconBadgeText(tabId); } + } + chrome.browserAction.setTitle({ + title: title && chrome.i18n.getMessage(title) || title || '', }); - colorScheme.onChange(val => { - isDark = val; - if (prefs.get('iconset') === -1) { - debounce(refreshAllIcons); - } - }, true); - bgReady.all.then(() => { - prefs.subscribe([ - 'disableAll', - 'badgeDisabled', - 'badgeNormal', - ], () => debounce(refreshIconBadgeColor), true); - prefs.subscribe([ - 'show-badge', - ], () => debounce(refreshAllIconsBadgeText), true); - prefs.subscribe([ - 'disableAll', - 'iconset', - ], () => debounce(refreshAllIcons), true); +} + +function onPortDisconnected({sender}) { + ignoreChromeError(); + if (tabMan.getStyleIds(sender.tab.id)) { + API.updateIconBadge.call({sender}, [], {lazyBadge: true}); + } +} + +function refreshIconBadgeText(tabId) { + if (badgeOvr.text) return; + const text = prefs.get('show-badge') ? `${getStyleCount(tabId)}` : ''; + setBadgeText({tabId, text}); +} + +function getIconName(hasStyles = false) { + const i = prefs.get('iconset'); + const prefix = i === 0 || i === -1 && isDark ? '' : 'light/'; + const postfix = prefs.get('disableAll') ? 'x' : !hasStyles ? 'w' : ''; + return `${prefix}$SIZE$${postfix}`; +} + +function refreshIcon(tabId, force = false) { + const oldIcon = tabMan.get(tabId, 'icon'); + const newIcon = getIconName(tabMan.getStyleIds(tabId)[0]); + // (changing the icon only for the main page, frameId = 0) + + if (!force && oldIcon === newIcon) { + return; + } + tabMan.set(tabId, 'icon', newIcon); + setIcon({ + path: getIconPath(newIcon), + tabId, }); +} - return { - /** Calling with no params clears the override */ - overrideBadge({text = '', color = '', title = ''} = {}) { - if (badgeOvr.text === text) { - return; - } - badgeOvr.text = text; - badgeOvr.color = color; - refreshIconBadgeColor(); - setBadgeText({text}); - for (const tabId of tabMan.keys()) { - if (text) { - setBadgeText({tabId, text}); - } else { - refreshIconBadgeText(tabId); - } - } - chrome.browserAction.setTitle({ - title: title && chrome.i18n.getMessage(title) || title || '', - }); +function getIconPath(icon) { + return ICON_SIZES.reduce( + (obj, size) => { + obj[size] = `/images/icon/${icon.replace('$SIZE$', size)}.png`; + return obj; }, - }; - - function onPortDisconnected({sender}) { - ignoreChromeError(); - if (tabMan.getStyleIds(sender.tab.id)) { - API.updateIconBadge.call({sender}, [], {lazyBadge: true}); - } - } - - function refreshIconBadgeText(tabId) { - if (badgeOvr.text) return; - const text = prefs.get('show-badge') ? `${getStyleCount(tabId)}` : ''; - setBadgeText({tabId, text}); - } - - function getIconName(hasStyles = false) { - const i = prefs.get('iconset'); - const prefix = i === 0 || i === -1 && isDark ? '' : 'light/'; - const postfix = prefs.get('disableAll') ? 'x' : !hasStyles ? 'w' : ''; - return `${prefix}$SIZE$${postfix}`; - } - - function refreshIcon(tabId, force = false) { - const oldIcon = tabMan.get(tabId, 'icon'); - const newIcon = getIconName(tabMan.getStyleIds(tabId)[0]); - // (changing the icon only for the main page, frameId = 0) - - if (!force && oldIcon === newIcon) { - return; - } - tabMan.set(tabId, 'icon', newIcon); - setIcon({ - path: getIconPath(newIcon), - tabId, - }); - } - - function getIconPath(icon) { - return ICON_SIZES.reduce( - (obj, size) => { - obj[size] = `/images/icon/${icon.replace('$SIZE$', size)}.png`; - return obj; - }, - {} - ); - } - - /** @return {number | ''} */ - function getStyleCount(tabId) { - const allIds = new Set(); - const data = tabMan.getStyleIds(tabId) || {}; - Object.values(data).forEach(frameIds => frameIds.forEach(id => allIds.add(id))); - return allIds.size || ''; - } - - // Caches imageData for icon paths - async function loadImage(url) { - const {OffscreenCanvas} = !FIREFOX && self.createImageBitmap && self || {}; - const img = OffscreenCanvas - ? await createImageBitmap(await (await fetch(url)).blob()) - : await new Promise((resolve, reject) => - Object.assign(new Image(), { - src: url, - onload: e => resolve(e.target), - onerror: reject, - })); - const {width: w, height: h} = img; - const canvas = OffscreenCanvas - ? new OffscreenCanvas(w, h) - : Object.assign(document.createElement('canvas'), {width: w, height: h}); - const ctx = canvas.getContext('2d'); - ctx.drawImage(img, 0, 0, w, h); - const result = ctx.getImageData(0, 0, w, h); - imageDataCache.set(url, result); - return result; - } - - function refreshGlobalIcon() { - setIcon({ - path: getIconPath(getIconName()), - }); - } - - function refreshIconBadgeColor() { - setBadgeBackgroundColor({ - color: badgeOvr.color || - prefs.get(prefs.get('disableAll') ? 'badgeDisabled' : 'badgeNormal'), - }); - } - - function refreshAllIcons() { - for (const tabId of tabMan.keys()) { - refreshIcon(tabId); - } - refreshGlobalIcon(); - } - - function refreshAllIconsBadgeText() { - for (const tabId of tabMan.keys()) { - refreshIconBadgeText(tabId); - } - } - - function refreshStaleBadges() { - for (const tabId of staleBadges) { - refreshIconBadgeText(tabId); - } - staleBadges.clear(); - } + {} + ); +} + +/** @return {number | ''} */ +function getStyleCount(tabId) { + const allIds = new Set(); + const data = tabMan.getStyleIds(tabId) || {}; + Object.values(data).forEach(frameIds => frameIds.forEach(id => allIds.add(id))); + return allIds.size || ''; +} + +// Caches imageData for icon paths +async function loadImage(url) { + const {OffscreenCanvas} = CHROME && self.createImageBitmap && self || {}; + const img = OffscreenCanvas + ? await createImageBitmap(await (await fetch(url)).blob()) + : await new Promise((resolve, reject) => + Object.assign(new Image(), { + src: url, + onload: e => resolve(e.target), + onerror: reject, + })); + const {width: w, height: h} = img; + const canvas = OffscreenCanvas + ? new OffscreenCanvas(w, h) + : Object.assign(document.createElement('canvas'), {width: w, height: h}); + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0, w, h); + const result = ctx.getImageData(0, 0, w, h); + imageDataCache.set(url, result); + return result; +} + +function refreshGlobalIcon() { + setIcon({ + path: getIconPath(getIconName()), + }); +} - function safeCall(method, data) { - const {browserAction = {}} = chrome; - const fn = browserAction[method]; - if (fn) { - try { - // Chrome supports the callback since 67.0.3381.0, see https://crbug.com/451320 - fn.call(browserAction, data, ignoreChromeError); - } catch (e) { - // FIXME: skip pre-rendered tabs? - fn.call(browserAction, data); - } +function refreshIconBadgeColor() { + setBadgeBackgroundColor({ + color: badgeOvr.color || + prefs.get(prefs.get('disableAll') ? 'badgeDisabled' : 'badgeNormal'), + }); +} + +function refreshAllIcons() { + for (const tabId of tabMan.keys()) { + refreshIcon(tabId); + } + refreshGlobalIcon(); +} + +function refreshAllIconsBadgeText() { + for (const tabId of tabMan.keys()) { + refreshIconBadgeText(tabId); + } +} + +function refreshStaleBadges() { + for (const tabId of staleBadges) { + refreshIconBadgeText(tabId); + } + staleBadges.clear(); +} + +function safeCall(method, data) { + const {browserAction = {}} = chrome; + const fn = browserAction[method]; + if (fn) { + try { + // Chrome supports the callback since 67.0.3381.0, see https://crbug.com/451320 + fn.call(browserAction, data, ignoreChromeError); + } catch (e) { + // FIXME: skip pre-rendered tabs? + fn.call(browserAction, data); } } +} - /** @param {chrome.browserAction.TabIconDetails} data */ - async function setIcon(data) { - if (hasCanvas === true || await hasCanvas) { - data.imageData = {}; - for (const [key, url] of Object.entries(data.path)) { - data.imageData[key] = imageDataCache.get(url) || await loadImage(url); - } - delete data.path; +/** @param {chrome.browserAction.TabIconDetails} data */ +async function setIcon(data) { + if (hasCanvas === true || await hasCanvas) { + data.imageData = {}; + for (const [key, url] of Object.entries(data.path)) { + data.imageData[key] = imageDataCache.get(url) || await loadImage(url); } - safeCall('setIcon', data); + delete data.path; } + safeCall('setIcon', data); +} - /** @param {chrome.browserAction.BadgeTextDetails} data */ - function setBadgeText(data) { - safeCall('setBadgeText', data); - } +/** @param {chrome.browserAction.BadgeTextDetails} data */ +function setBadgeText(data) { + safeCall('setBadgeText', data); +} - /** @param {chrome.browserAction.BadgeBackgroundColorDetails} data */ - function setBadgeBackgroundColor(data) { - safeCall('setBadgeBackgroundColor', data); - } -})(); +/** @param {chrome.browserAction.BadgeBackgroundColorDetails} data */ +function setBadgeBackgroundColor(data) { + safeCall('setBadgeBackgroundColor', data); +} diff --git a/src/background/background.js b/src/background/index.js similarity index 64% rename from src/background/background.js rename to src/background/index.js index 8edd195bb0e..222a7e74ffe 100644 --- a/src/background/background.js +++ b/src/background/index.js @@ -1,16 +1,24 @@ -/* global API msg */// msg.js -/* global addAPI bgReady broadcastInjectorConfig detectVivaldi isVivaldi */// common.js -/* global createWorker */// worker-util.js -/* global prefs */ -/* global styleMan */ -/* global syncMan */ -/* global updateMan */ -/* global usercssMan */ -/* global usoApi */ -/* global uswApi */ -/* global FIREFOX UA ignoreChromeError */ // toolbox.js -/* global colorScheme */ // color-scheme.js -'use strict'; +import browser from '/js/browser'; +import * as msg from '/js/msg'; +import * as prefs from '/js/prefs'; +import {ignoreChromeError, UA} from '/js/toolbox'; +import createWorker from '/js/worker-host'; +import {bgPrefsSet} from './bg-prefs'; +import {broadcast} from './broadcast'; +import broadcastInjectorConfig, {INJECTOR_CONFIG_MAP} from './broadcast-injector-config'; +import * as colorScheme from './color-scheme'; +import {addAPI, API, bgReady, browserCommands, detectVivaldi, isVivaldi} from './common'; +import download from './download'; +import './browser-cmd-hotkeys'; +import './content-scripts'; +import './context-menus'; +import * as styleMan from './style-manager'; +import * as syncMan from './sync-manager'; +import * as updateMan from './update-manager'; +import * as usercssMan from './usercss-manager'; +import * as usoApi from './uso-api'; +import * as uswApi from './usw-api'; +import './style-via-api'; //#region API @@ -31,6 +39,8 @@ addAPI(/** @namespace API */ { }, }))(), + download, + info: { async get() { return { @@ -57,14 +67,14 @@ addAPI(/** @namespace API */ { //#endregion //#region Events -const browserCommands = { +Object.assign(browserCommands, { openManage: () => API.openManage(), openOptions: () => API.openManage({options: true}), reload: () => chrome.runtime.reload(), styleDisableAll(info) { - prefs.set('disableAll', info ? info.checked : !prefs.get('disableAll')); + bgPrefsSet('disableAll', info ? info.checked : !prefs.get('disableAll')); }, -}; +}); if (chrome.commands) { chrome.commands.onCommand.addListener(id => browserCommands[id]()); @@ -72,8 +82,8 @@ if (chrome.commands) { chrome.runtime.onInstalled.addListener(({reason, previousVersion}) => { if (reason === 'install') { - if (UA.mobile) prefs.set('manage.newUI', false); - if (UA.windows) prefs.set('editor.keyMap', 'sublime'); + if (UA.mobile) bgPrefsSet('manage.newUI', false); + if (UA.windows) bgPrefsSet('editor.keyMap', 'sublime'); } if (previousVersion === '1.5.30') { API.prefsDb.delete('badFavs'); // old Stylus marked all icons as bad when network was offline @@ -98,11 +108,11 @@ chrome.runtime.onConnect.addListener(port => { async function apiPortMessage({id, data, TDM}, port) { try { - if (!msg.ready) await bgReady.all; + if (!self.msg) await bgReady.all; port.sender.TDM = TDM; data = {data: await msg._execute('extension', data, port.sender)}; } catch (e) { - data = msg._wrapError(e); + data = msg.wrapError(e); } data.id = id; try { port.postMessage(data); } catch (e) {} @@ -114,20 +124,10 @@ Promise.all([ browser.extension.isAllowedFileSchemeAccess() .then(res => API.data.set('hasFileAccess', res)), bgReady.styles, - /* These are loaded conditionally. - Each item uses `require` individually so IDE can jump to the source and track usage. */ - FIREFOX && - require(['/background/style-via-api']), - FIREFOX && ((browser.commands || {}).update) && - require(['/background/browser-cmd-hotkeys']), - !FIREFOX && - require(['/background/content-scripts']), - chrome.contextMenus && - require(['/background/context-menus']), ]).then(() => { bgReady._resolveAll(true); - msg.ready = true; - msg.broadcast({method: 'backgroundReady'}); - prefs.subscribe(['disableAll', 'exposeIframes', 'styleViaASS'], broadcastInjectorConfig); + self.msg = msg; + broadcast({method: 'backgroundReady'}); + prefs.subscribe(Object.keys(INJECTOR_CONFIG_MAP), broadcastInjectorConfig); colorScheme.onChange(broadcastInjectorConfig.bind(null, 'dark')); }); diff --git a/src/background/navigation-manager.js b/src/background/navigation-manager.js index e90778c7b09..be12f036687 100644 --- a/src/background/navigation-manager.js +++ b/src/background/navigation-manager.js @@ -1,57 +1,49 @@ -/* global CHROME FIREFOX URLS deepEqual ignoreChromeError */// toolbox.js -/* global bgReady */// common.js -/* global msg */ -/* global tabMan */ -'use strict'; +import browser from '/js/browser'; +import {sendTab} from '/js/msg'; +import {CHROME, deepEqual, FIREFOX, ignoreChromeError, URLS} from '/js/toolbox'; +import {bgReady} from './common'; +import tabMan from './tab-manager'; -/* exported navMan */ -const navMan = (() => { - const listeners = new Set(); - let prevData = {}; +const listeners = new Set(); +/** @param {function(data: Object, type: ('committed'|'history'|'hash'))} fn */ +export const onUrlChange = fn => listeners.add(fn); +let prevData = {}; - chrome.webNavigation.onCommitted.addListener(onNavigation.bind('committed')); - chrome.webNavigation.onHistoryStateUpdated.addListener(onFakeNavigation.bind('history')); - chrome.webNavigation.onReferenceFragmentUpdated.addListener(onFakeNavigation.bind('hash')); +chrome.webNavigation.onCommitted.addListener(onNavigation.bind('committed')); +chrome.webNavigation.onHistoryStateUpdated.addListener(onFakeNavigation.bind('history')); +chrome.webNavigation.onReferenceFragmentUpdated.addListener(onFakeNavigation.bind('hash')); - return { - /** @param {function(data: Object, type: ('committed'|'history'|'hash'))} fn */ - onUrlChange(fn) { - listeners.add(fn); - }, - }; - - /** @this {string} type */ - async function onNavigation(data) { - if (CHROME && data.timeStamp === prevData.timeStamp && deepEqual(data, prevData)) { - return; // Chrome bug: listener is called twice with identical data - } - prevData = data; - if (CHROME && - URLS.chromeProtectsNTP && - data.url.startsWith('https://www.google.') && - data.url.includes('/_/chrome/newtab?')) { - // Modern Chrome switched to WebUI NTP so this is obsolete, but there may be exceptions - // TODO: investigate, and maybe use a separate listener for CHROME <= ver - const tab = await browser.tabs.get(data.tabId); - const url = tab.pendingUrl || tab.url; - if (url === 'chrome://newtab/') { - data.url = url; - } +/** @this {string} type */ +async function onNavigation(data) { + if (CHROME && data.timeStamp === prevData.timeStamp && deepEqual(data, prevData)) { + return; // Chrome bug: listener is called twice with identical data + } + prevData = data; + if (CHROME && + URLS.chromeProtectsNTP && + data.url.startsWith('https://www.google.') && + data.url.includes('/_/chrome/newtab?')) { + // Modern Chrome switched to WebUI NTP so this is obsolete, but there may be exceptions + // TODO: investigate, and maybe use a separate listener for CHROME <= ver + const tab = await browser.tabs.get(data.tabId); + const url = tab.pendingUrl || tab.url; + if (url === 'chrome://newtab/') { + data.url = url; } - listeners.forEach(fn => fn(data, this)); } + listeners.forEach(fn => fn(data, this)); +} - /** @this {string} type */ - function onFakeNavigation(data) { - onNavigation.call(this, data); - const {tabId} = data; - const td = tabMan.get(tabId); if (!td) return; - const {url, frameId: f, documentId: d} = data; - const iid = !d && (td.iid || {})[f]; - const to = d ? {documentId: d} : {frameId: f}; - msg.sendTab(tabId, {method: 'urlChanged', iid, url}, to); - } -})(); +/** @this {string} type */ +function onFakeNavigation(data) { + onNavigation.call(this, data); + const {tabId} = data; + const td = tabMan.get(tabId); if (!td) return; + const {url, frameId: f, documentId: d} = data; + const iid = !d && (td.iid || {})[f]; + const to = d ? {documentId: d} : {frameId: f}; + sendTab(tabId, {method: 'urlChanged', iid, url}, to); +} bgReady.all.then(() => { /* @@ -91,7 +83,7 @@ bgReady.all.then(() => { if (FIREFOX) { chrome.webNavigation.onDOMContentLoaded.addListener(async ({tabId, frameId}) => { if (frameId && - !await msg.sendTab(tabId, {method: 'ping'}, {frameId})) { + !await sendTab(tabId, {method: 'ping'}, {frameId})) { for (const file of chrome.runtime.getManifest().content_scripts[0].js) { chrome.tabs.executeScript(tabId, { frameId, diff --git a/src/background/style-cache.js b/src/background/style-cache.js new file mode 100644 index 00000000000..07959bcd999 --- /dev/null +++ b/src/background/style-cache.js @@ -0,0 +1,60 @@ +/** Creates a FIFO limit-size map. */ +export default function StyleCache({size = 1000, onDeleted} = {}) { + const map = new Map(); + const buffer = Array(size); + let index = 0; + let lastIndex = 0; + return { + get(id) { + const item = map.get(id); + return item && item.data; + }, + set(id, data) { + if (map.size === size) { + // full + map.delete(buffer[lastIndex].id); + if (onDeleted) { + onDeleted(buffer[lastIndex].id, buffer[lastIndex].data); + } + lastIndex = (lastIndex + 1) % size; + } + const item = {id, data, index}; + map.set(id, item); + buffer[index] = item; + index = (index + 1) % size; + }, + delete(id) { + const item = map.get(id); + if (!item) { + return false; + } + map.delete(item.id); + const lastItem = buffer[lastIndex]; + lastItem.index = item.index; + buffer[item.index] = lastItem; + lastIndex = (lastIndex + 1) % size; + if (onDeleted) { + onDeleted(item.id, item.data); + } + return true; + }, + clear() { + map.clear(); + index = lastIndex = 0; + }, + has: id => map.has(id), + *entries() { + for (const [id, item] of map) { + yield [id, item.data]; + } + }, + *values() { + for (const item of map.values()) { + yield item.data; + } + }, + get size() { + return map.size; + }, + }; +} diff --git a/src/background/style-manager.js b/src/background/style-manager.js index 5d04ad4f83b..1305a3ab43d 100644 --- a/src/background/style-manager.js +++ b/src/background/style-manager.js @@ -1,833 +1,818 @@ -/* global API msg */// msg.js -/* global CHROME UCD URLS deepEqual isEmptyObj mapObj stringAsRegExpStr tryRegExp tryURL */// toolbox.js -/* global bgReady broadcastInjectorConfig createCache uuidIndex */// common.js -/* global calcStyleDigest styleCodeEmpty */// sections-util.js -/* global db */ -/* global prefs */ -/* global tabMan */ -/* global getUrlOrigin */// tab-util.js -/* global usercssMan */ -/* global colorScheme */ -'use strict'; - -const styleUtil = {}; - -/* exported styleMan */ -const styleMan = (() => { - - //#region Declarations - - /** @type {Map} */ - const dataMap = new Map(); - /** @type {Map} */ - const cachedStyleForUrl = createCache({ - onDeleted(url, {sections}) { - for (const id in sections) { - const data = id2data(id); - if (data) data.appliesTo.delete(url); - } - }, - }); - const BAD_MATCHER = {test: () => false}; - const compileRe = createCompiler(text => `^(${text})$`); - const compileSloppyRe = createCompiler(text => `^${text}$`); - const compileExclusion = createCompiler(buildExclusion); - - const uuidv4 = crypto.randomUUID ? crypto.randomUUID.bind(crypto) : (() => { - const seeds = crypto.getRandomValues(new Uint16Array(8)); - // 00001111-2222-M333-N444-555566667777 - seeds[3] = seeds[3] & 0x0FFF | 0x4000; // UUID version 4, M = 4 - seeds[4] = seeds[4] & 0x3FFF | 0x8000; // UUID variant 1, N = 8..0xB - return Array.from(seeds, hex4dashed).join(''); - }); - - const CFG_OFF = {cfg: {off: true}}; - const MISSING_PROPS = { - name: style => `ID: ${style.id}`, - _id: () => uuidv4(), - _rev: () => Date.now(), - }; - - const ON_DISCONNECT = { - livePreview: onPreviewEnd, - draft: onDraftEnd, - }; - - const INJ_ORDER = 'injectionOrder'; - const order = /** @type {InjectionOrder} */{main: {}, prio: {}}; - const orderWrap = { - id: INJ_ORDER, - value: mapObj(order, () => []), - _id: `${chrome.runtime.id}-${INJ_ORDER}`, - _rev: 0, - }; - uuidIndex.addCustom(orderWrap, {set: setOrder}); - - Object.assign(styleUtil, { - handleSave, - id2style, - iterStyles, - uuid2style, - order, +import * as prefs from '/js/prefs'; +import {calcStyleDigest, styleCodeEmpty} from '/js/sections-util'; +import { + deepEqual, isEmptyObj, mapObj, stringAsRegExpStr, tryRegExp, tryURL, UCD, URLS, +} from '/js/toolbox'; +import {broadcast, broadcastExtension} from './broadcast'; +import broadcastInjectorConfig from './broadcast-injector-config'; +import * as colorScheme from './color-scheme'; +import {API, bgReady, uuidIndex} from './common'; +import db from './db'; +import StyleCache from './style-cache'; +import tabMan from './tab-manager'; +import {getUrlOrigin} from './tab-util'; + +//#region Declarations + +/** @type {Map} */ +const dataMap = new Map(); +/** @type {Map} */ +const cachedStyleForUrl = StyleCache({ + onDeleted(url, {sections}) { + for (const id in sections) { + const data = id2data(id); + if (data) data.appliesTo.delete(url); + } + }, +}); +const BAD_MATCHER = {test: () => false}; +const compileRe = createCompiler(text => `^(${text})$`); +const compileSloppyRe = createCompiler(text => `^${text}$`); +const compileExclusion = createCompiler(buildExclusion); + +const uuidv4 = crypto.randomUUID ? crypto.randomUUID.bind(crypto) : (() => { + const seeds = crypto.getRandomValues(new Uint16Array(8)); + // 00001111-2222-M333-N444-555566667777 + seeds[3] = seeds[3] & 0x0FFF | 0x4000; // UUID version 4, M = 4 + seeds[4] = seeds[4] & 0x3FFF | 0x8000; // UUID variant 1, N = 8..0xB + return Array.from(seeds, hex4dashed).join(''); +}); + +const CFG_OFF = {cfg: {off: true}}; +const MISSING_PROPS = { + name: style => `ID: ${style.id}`, + _id: () => uuidv4(), + _rev: () => Date.now(), +}; + +const ON_DISCONNECT = { + livePreview: onPreviewEnd, + draft: onDraftEnd, +}; + +const INJ_ORDER = 'injectionOrder'; +export const order = /** @type {InjectionOrder} */{main: {}, prio: {}}; +const orderWrap = { + id: INJ_ORDER, + value: mapObj(order, () => []), + _id: `${chrome.runtime.id}-${INJ_ORDER}`, + _rev: 0, +}; +/** @returns {{[type: string]: string[]}}>} */ +export const getOrder = () => orderWrap.value; +uuidIndex.addCustom(orderWrap, {set: setOrderImpl}); + +class MatchQuery { + constructor(url) { + this.url = url; + } + get urlWithoutHash() { + return this._set('urlWithoutHash', this.url.split('#', 1)[0]); + } + get urlWithoutParams() { + return this._set('urlWithoutParams', this.url.split(/[?#]/, 1)[0]); + } + get domain() { + return this._set('domain', tryURL(this.url).hostname); + } + get isOwnPage() { + return this._set('isOwnPage', this.url.startsWith(URLS.ownOrigin)); + } + _set(name, value) { + Object.defineProperty(this, name, {value}); + return value; + } +} + +init(); + +chrome.runtime.onConnect.addListener(port => { + // Using ports to reliably track when the client is closed, however not for messaging, + // because our `API` is much faster due to direct invocation. + const type = port.name.split(':', 1)[0]; + const fn = ON_DISCONNECT[type]; + if (fn) port.onDisconnect.addListener(fn); +}); +bgReady.all.then(() => colorScheme.onChange(value => { + broadcastExtension({method: 'colorScheme', value}); + for (const {style} of dataMap.values()) { + if (colorScheme.SCHEMES.includes(style.preferScheme)) { + broadcastStyleUpdated(style, 'colorScheme'); + } + } +}, true)); + +//#endregion +//#region Exports + +/** @returns {number} style id */ +export function remove(id, reason) { + const {style, appliesTo} = dataMap.get(id); + const sync = reason !== 'sync'; + const uuid = style._id; + db.styles.delete(id); + if (sync) API.sync.remove(uuid, Date.now()); + for (const url of appliesTo) { + const cache = cachedStyleForUrl.get(url); + if (cache) delete cache.sections[id]; + } + dataMap.delete(id); + uuidIndex.delete(uuid); + mapObj(orderWrap.value, (group, type) => { + delete order[type][id]; + const i = group.indexOf(uuid); + if (i >= 0) group.splice(i, 1); }); - - class MatchQuery { - constructor(url) { - this.url = url; - } - get urlWithoutHash() { - return this._set('urlWithoutHash', this.url.split('#', 1)[0]); - } - get urlWithoutParams() { - return this._set('urlWithoutParams', this.url.split(/[?#]/, 1)[0]); - } - get domain() { - return this._set('domain', tryURL(this.url).hostname); - } - get isOwnPage() { - return this._set('isOwnPage', this.url.startsWith(URLS.ownOrigin)); - } - _set(name, value) { - Object.defineProperty(this, name, {value}); - return value; + setOrderImpl(orderWrap, {calc: false}); + if (style._usw && style._usw.token) { + // Must be called after the style is deleted from dataMap + API.usw.revoke(id); + } + API.drafts.delete(id).catch(() => {}); + broadcast({ + method: 'styleDeleted', + style: {id}, + }, {onlyIfStyled: true}); + return id; +} + +/** @returns {Promise} */ +export function editSave(style) { + style = mergeWithMapped(style); + style.updateDate = Date.now(); + API.drafts.delete(style.id).catch(() => {}); + return saveStyle(style, 'editSave'); +} + +/** @returns {StyleObj|void} */ +export function find(filter, subkey) { + for (const {style} of dataMap.values()) { + let obj = subkey ? style[subkey] : style; + if (!obj) continue; + for (const key in filter) { + if (filter[key] !== obj[key]) { + obj = null; + break; + } } + if (obj) return style; } +} - init(); +export const getAll = () => Array.from(dataMap.values(), v => v.style); - chrome.runtime.onConnect.addListener(port => { - // Using ports to reliably track when the client is closed, however not for messaging, - // because our `API` is much faster due to direct invocation. - const type = port.name.split(':', 1)[0]; - const fn = ON_DISCONNECT[type]; - if (fn) port.onDisconnect.addListener(fn); - }); - bgReady.all.then(() => colorScheme.onChange(value => { - msg.broadcastExtension({method: 'colorScheme', value}); +/** @returns {{[type: string]: StyleObj[]}}>} */ +export function getAllOrdered(keys) { + const res = mapObj(orderWrap.value, group => group.map(uuid2style).filter(Boolean)); + if (res.main.length + res.prio.length < dataMap.size) { for (const {style} of dataMap.values()) { - if (colorScheme.SCHEMES.includes(style.preferScheme)) { - broadcastStyleUpdated(style, 'colorScheme'); + if (!(style.id in order.main) && !(style.id in order.prio)) { + res.main.push(style); } } - }, true)); - - //#endregion - //#region Exports - - return { - /** @returns {number} style id */ - delete(id, reason) { - const {style, appliesTo} = dataMap.get(id); - const sync = reason !== 'sync'; - const uuid = style._id; - db.styles.delete(id); - if (sync) API.sync.delete(uuid, Date.now()); - for (const url of appliesTo) { - const cache = cachedStyleForUrl.get(url); - if (cache) delete cache.sections[id]; - } - dataMap.delete(id); - uuidIndex.delete(uuid); - mapObj(orderWrap.value, (group, type) => { - delete order[type][id]; - const i = group.indexOf(uuid); - if (i >= 0) group.splice(i, 1); - }); - setOrder(orderWrap, {calc: false}); - if (style._usw && style._usw.token) { - // Must be called after the style is deleted from dataMap - API.usw.revoke(id); - } - API.drafts.delete(id).catch(() => {}); - msg.broadcast({ - method: 'styleDeleted', - style: {id}, - }, {onlyIfStyled: true}); - return id; - }, - - /** @returns {Promise} */ - editSave(style) { - style = mergeWithMapped(style); - style.updateDate = Date.now(); - API.drafts.delete(style.id).catch(() => {}); - return saveStyle(style, 'editSave'); - }, - - /** @returns {StyleObj|void} */ - find(filter, subkey) { - for (const {style} of dataMap.values()) { - let obj = subkey ? style[subkey] : style; - if (!obj) continue; - for (const key in filter) { - if (filter[key] !== obj[key]) { - obj = null; - break; - } - } - if (obj) return style; - } - }, - - getAll: () => Array.from(dataMap.values(), v => v.style), - - /** @returns {{[type: string]: StyleObj[]}}>} */ - getAllOrdered(keys) { - const res = mapObj(orderWrap.value, group => group.map(uuid2style).filter(Boolean)); - if (res.main.length + res.prio.length < dataMap.size) { - for (const {style} of dataMap.values()) { - if (!(style.id in order.main) && !(style.id in order.prio)) { - res.main.push(style); - } - } - } - return keys - ? mapObj(res, group => group.map(style => mapObj(style, null, keys))) - : res; - }, - - /** @returns {{[type: string]: string[]}}>} */ - getOrder: () => orderWrap.value, - - /** @returns {string | {[remoteId:string]: styleId}}>} */ - getRemoteInfo(id) { - if (id) return calcRemoteId(id2style(id)); - const res = {}; - for (const {style} of dataMap.values()) { - const [rid, vars] = calcRemoteId(style); - if (rid) res[rid] = [style.id, vars]; - } - return res; - }, - - /** @returns {Injection} */ - getSectionsByUrl(url, id, isInitialApply) { - const p = prefs.__values; - if (isInitialApply && p.disableAll) { - return CFG_OFF; - } - const {sender = {}} = this || {}; - const {tab = {}, frameId, TDM} = sender; - const isTop = !frameId || TDM || sender.type === 'main_frame'; // prerendering in onBeforeRequest - /** @type {InjectionConfig} */ - const cfg = !id && { - ass: p.styleViaASS, - dark: isTop && colorScheme.isDark(), - // TODO: enable in FF when it supports sourceURL comment in style elements (also options.html) - name: CHROME && p.exposeStyleName, - nonce: !CHROME && tabMan.get(tab.id, 'nonce', frameId), - top: isInitialApply && p.exposeIframes && ( - isTop ? '' // apply.js will use location.origin - : getUrlOrigin(tab.url || tabMan.get(sender.tabId || tab.id, 'url')) - ), - order, - }; - if (isInitialApply === 'cfg') { - return {cfg}; - } - if (frameId === 0) { - /* Chrome hides text frament from location.href of the page e.g. #:~:text=foo - so we'll use the real URL reported by webNavigation API. - TODO: if FF will do the same, this won't work as is: FF reports onCommitted too late */ - url = tabMan.get(tab.id, 'url') || url; - } - /** @type {CachedInjectedStyles} */ - let cache = cachedStyleForUrl.get(url); - if (!cache) { - cache = { - sections: {}, - maybeMatch: new Set(), - }; - buildCache(cache, url, dataMap.values()); - cachedStyleForUrl.set(url, cache); - } else if (cache.maybeMatch.size) { - buildCache(cache, url, Array.from(cache.maybeMatch, id2data).filter(Boolean)); - } - let res = cache.sections; - return { - cfg, - sections: id - ? ((res = res[id])) ? [res] : [] - : Object.values(res), - }; - }, - - /** @returns {StyleObj} */ - get: id2style, - - /** @returns {StylesByUrlResult[]} */ - getByUrl(url, id = null) { - // FIXME: do we want to cache this? Who would like to open popup rapidly - // or search the DB with the same URL? - const result = []; - const styles = id - ? [id2style(id)].filter(Boolean) - : iterStyles(); - const query = new MatchQuery(url); - for (const style of styles) { - let empty = true; - let excluded = false; - let excludedScheme = false; - let included = false; - let sloppy = false; - let sectionMatched = false; - const match = urlMatchStyle(query, style); - // TODO: enable this when the function starts returning false - // if (match === false) { - // continue; - // } - if (match === 'included') { - included = true; - } - if (match === 'excluded') { - excluded = true; - } - if (match === 'excludedScheme') { - excludedScheme = true; - } - for (const section of style.sections) { - const match = urlMatchSection(query, section, true); - if (match) { - if (match === 'sloppy') { - sloppy = true; - } - sectionMatched = true; - if (empty) empty = styleCodeEmpty(section); - } - } - if (sectionMatched || included) { - result.push(/** @namespace StylesByUrlResult */ { - empty, - excluded, - excludedScheme, - included, - sectionMatched, - sloppy, - style, - }); - } - } - return result; - }, - - /** @returns {Promise<{style?:StyleObj, err?:?}[]>} */ - async importMany(items) { - const res = []; - const styles = []; - for (const style of items) { - try { - beforeSave(style); - if (style.sourceCode && style[UCD]) { - await usercssMan.buildCode(style); - } - res.push(styles.push(style) - 1); - } catch (err) { - res.push({err}); - } - } - const events = await db.styles.putMany(styles); - const messages = []; - for (let i = 0, r; i < res.length; i++) { - r = res[i]; - if (!r.err) { - const id = events[r]; - const method = dataMap.has(id) ? 'styleUpdated' : 'styleAdded'; - const style = handleSave(styles[r], false, id); - messages.push([style, 'import', method]); - buildCacheForStyle(style); - res[i] = {style}; - } - } - setTimeout(() => messages.forEach(args => broadcastStyleUpdated(...args)), 100); - return Promise.all(res); - }, - - /** @returns {Promise} */ - async install(style, reason = dataMap.has(style.id) ? 'update' : 'install') { - style = mergeWithMapped(style); - style.originalDigest = await calcStyleDigest(style); - // FIXME: update updateDate? what about usercss config? - return saveStyle(style, reason); - }, - - /** @param {StyleObj} style */ - async preview(style) { - let res = style.sourceCode || false; - if (res) { - res = await usercssMan.build({ - styleId: style.id, - sourceCode: res, - assignVars: true, - }); - delete res.style.enabled; - Object.assign(style, res.style); - } - id2data(style.id).preview = style; - broadcastStyleUpdated(style, 'editPreview'); - return res.log; - }, - - /** @returns {Promise} */ - save: saveStyle, - - /** @returns {Promise} */ - setOrder(value) { - return setOrder({value}, {broadcast: true, sync: true}); - }, - - /** @returns {Promise} */ - async toggle(id, enabled) { - const style = Object.assign({}, id2style(id), {enabled}); - await saveStyle(style, 'toggle'); - }, - - /** @returns {Promise} */ - async toggleOverride(id, rule, isInclusion, isAdd) { - const style = Object.assign({}, id2style(id)); - const type = isInclusion ? 'inclusions' : 'exclusions'; - let list = style[type]; - if (isAdd) { - if (!list) list = style[type] = []; - else if (list.includes(rule)) throw new Error('The rule already exists'); - list.push(rule); - } else if (list) { - const i = list.indexOf(rule); - if (i >= 0) list.splice(i, 1); - } else { - return; - } - cachedStyleForUrl.clear(); - await saveStyle(style, 'config'); - }, - - /** @returns {Promise} */ - async config(id, prop, value) { - const style = Object.assign({}, id2style(id)); - const {preview} = dataMap.get(id); - style[prop] = (preview || {})[prop] = value; - if (prop === 'inclusions' || prop === 'exclusions') cachedStyleForUrl.clear(); - await saveStyle(style, 'config'); - }, - }; - - //#endregion - //#region Implementation - - /** @returns {StyleMapData|void} */ - function id2data(id) { - return dataMap.get(id); } - - /** @returns {StyleObj|void} */ - function id2style(id) { - return (dataMap.get(Number(id)) || {}).style; - } - - /** @returns {StyleObj|void} */ - function uuid2style(uuid) { - return id2style(uuidIndex.get(uuid)); - } - - function calcRemoteId({md5Url, updateUrl, [UCD]: ucd} = {}) { - let id; - id = (id = /\d+/.test(md5Url) || URLS.extractUsoaId(updateUrl)) && `uso-${id}` - || (id = URLS.extractUswId(updateUrl)) && `usw-${id}` - || ''; - return id && [ - id, - ucd && !isEmptyObj(ucd.vars), - ]; - } - - /** @returns {StyleObj} */ - function createNewStyle() { - return { - enabled: true, - installDate: Date.now(), + return keys + ? mapObj(res, group => group.map(style => mapObj(style, null, keys))) + : res; +} + +/** @returns {string | {[remoteId:string]: styleId}}>} */ +export function getRemoteInfo(id) { + if (id) return calcRemoteId(id2style(id)); + const res = {}; + for (const {style} of dataMap.values()) { + const [rid, vars] = calcRemoteId(style); + if (rid) res[rid] = [style.id, vars]; + } + return res; +} + +/** @returns {Injection} */ +export function getSectionsByUrl(url, id, isInitialApply) { + const p = prefs.__values; + if (isInitialApply && p.disableAll) { + return CFG_OFF; + } + const {sender = {}} = this || {}; + const {tab = {}, frameId, TDM} = sender; + const isTop = !frameId || TDM || sender.type === 'main_frame'; // prerendering in onBeforeRequest + /** @type {InjectionConfig} */ + const cfg = !id && { + ass: p.styleViaASS, + dark: isTop && colorScheme.isDark(), + // TODO: enable in FF when it supports sourceURL comment in style elements (also options.html) + name: CHROME && p.exposeStyleName, + nonce: FIREFOX && tabMan.get(tab.id, 'nonce', frameId), + top: isInitialApply && p.exposeIframes && ( + isTop ? '' // apply.js will use location.origin + : getUrlOrigin(tab.url || tabMan.get(sender.tabId || tab.id, 'url')) + ), + order, + }; + if (isInitialApply === 'cfg') { + return {cfg}; + } + if (frameId === 0) { + /* Chrome hides text frament from location.href of the page e.g. #:~:text=foo + so we'll use the real URL reported by webNavigation API. + TODO: if FF will do the same, this won't work as is: FF reports onCommitted too late */ + url = tabMan.get(tab.id, 'url') || url; + } + /** @type {CachedInjectedStyles} */ + let cache = cachedStyleForUrl.get(url); + if (!cache) { + cache = { + sections: {}, + maybeMatch: new Set(), }; + buildCache(cache, url, dataMap.values()); + cachedStyleForUrl.set(url, cache); + } else if (cache.maybeMatch.size) { + buildCache(cache, url, Array.from(cache.maybeMatch, id2data).filter(Boolean)); } - - /** @returns {void} */ - function storeInMap(style) { - dataMap.set(style.id, { - style, - appliesTo: new Set(), - }); - uuidIndex.set(style._id, style.id); - } - - /** @returns {StyleObj} */ - function mergeWithMapped(style) { - return Object.assign({}, - id2style(style.id) || createNewStyle(), - style); - } - - function onDraftEnd(port) { - const id = port.name.split(':')[1]; - API.drafts.delete(+id || id).catch(() => {}); - } - - function onPreviewEnd({name}) { - const id = +name.split(':')[1]; - const data = id2data(id); - if (!data) return; - data.preview = null; - broadcastStyleUpdated(data.style, 'editPreviewEnd'); - } - - function buildCacheForStyle(style) { - const {id} = style; - const data = id2data(id); - // FIXME: ideally, when preview is available, there is no need to rebuild the cache when original style change. - // we should lift this logic to parent function. - const styleToApply = data.preview || style; - const excluded = new Set(); - const updated = new Set(); - for (const [url, cache] of cachedStyleForUrl.entries()) { - if (!data.appliesTo.has(url)) { - cache.maybeMatch.add(id); - continue; - } - const code = getAppliedCode(new MatchQuery(url), styleToApply); - if (code) { - updated.add(url); - buildCacheEntry(cache, styleToApply, code); - } else { - excluded.add(url); - delete cache.sections[id]; + let res = cache.sections; + return { + cfg, + sections: id + ? ((res = res[id])) ? [res] : [] + : Object.values(res), + }; +} + +/** @returns {StylesByUrlResult[]} */ +export function getByUrl(url, id = null) { + // FIXME: do we want to cache this? Who would like to open popup rapidly + // or search the DB with the same URL? + const result = []; + const styles = id + ? [id2style(id)].filter(Boolean) + : iterStyles(); + const query = new MatchQuery(url); + for (const style of styles) { + let empty = true; + let excluded = false; + let excludedScheme = false; + let included = false; + let sloppy = false; + let sectionMatched = false; + const match = urlMatchStyle(query, style); + // TODO: enable this when the function starts returning false + // if (match === false) { + // continue; + // } + if (match === 'included') { + included = true; + } + if (match === 'excluded') { + excluded = true; + } + if (match === 'excludedScheme') { + excludedScheme = true; + } + for (const section of style.sections) { + const match = urlMatchSection(query, section, true); + if (match) { + if (match === 'sloppy') { + sloppy = true; + } + sectionMatched = true; + if (empty) empty = styleCodeEmpty(section); } } - data.appliesTo = updated; + if (sectionMatched || included) { + result.push(/** @namespace StylesByUrlResult */ { + empty, + excluded, + excludedScheme, + included, + sectionMatched, + sloppy, + style, + }); + } } + return result; +} - function broadcastStyleUpdated(style, reason, isNew) { - buildCacheForStyle(style); - return msg.broadcast({ - method: isNew ? 'styleAdded' : 'styleUpdated', - reason, - style: { - id: style.id, - enabled: style.enabled, - }, - }, {onlyIfStyled: !style.enabled}); - } +/** @returns {Promise<{style?:StyleObj, err?:?}[]>} */ +export async function importMany(items) { + const res = []; + const styles = []; + for (const style of items) { + try { + beforeSave(style); + if (style.sourceCode && style[UCD]) { + await API.usercss.buildCode(style); + } + res.push(styles.push(style) - 1); + } catch (err) { + res.push({err}); + } + } + const events = await db.styles.putMany(styles); + const messages = []; + for (let i = 0, r; i < res.length; i++) { + r = res[i]; + if (!r.err) { + const id = events[r]; + const method = dataMap.has(id) ? 'styleUpdated' : 'styleAdded'; + const style = handleSave(styles[r], false, id); + messages.push([style, 'import', method]); + buildCacheForStyle(style); + res[i] = {style}; + } + } + setTimeout(() => messages.forEach(args => broadcastStyleUpdated(...args)), 100); + return Promise.all(res); +} + +/** @returns {Promise} */ +export async function install(style, reason = dataMap.has(style.id) ? 'update' : 'install') { + style = mergeWithMapped(style); + style.originalDigest = await calcStyleDigest(style); + // FIXME: update updateDate? what about usercss config? + return saveStyle(style, reason); +} + +/** @param {StyleObj} style */ +export async function preview(style) { + let res = style.sourceCode || false; + if (res) { + res = await API.usercss.build({ + styleId: style.id, + sourceCode: res, + assignVars: true, + }); + delete res.style.enabled; + Object.assign(style, res.style); + } + id2data(style.id).preview = style; + broadcastStyleUpdated(style, 'editPreview'); + return res.log; +} + +/** @returns {Promise} */ +export function setOrder(value) { + return setOrderImpl({value}, {broadcast: true, sync: true}); +} + +/** @returns {Promise} */ +export async function toggle(id, enabled) { + const style = Object.assign({}, id2style(id), {enabled}); + await saveStyle(style, 'toggle'); +} + +/** @returns {Promise} */ +export async function toggleOverride(id, rule, isInclusion, isAdd) { + const style = Object.assign({}, id2style(id)); + const type = isInclusion ? 'inclusions' : 'exclusions'; + let list = style[type]; + if (isAdd) { + if (!list) list = style[type] = []; + else if (list.includes(rule)) throw new Error('The rule already exists'); + list.push(rule); + } else if (list) { + const i = list.indexOf(rule); + if (i >= 0) list.splice(i, 1); + } else { + return; + } + cachedStyleForUrl.clear(); + await saveStyle(style, 'config'); +} + +/** @returns {Promise} */ +export async function config(id, prop, value) { + const style = Object.assign({}, id2style(id)); + const {preview} = dataMap.get(id); + style[prop] = (preview || {})[prop] = value; + if (prop === 'inclusions' || prop === 'exclusions') cachedStyleForUrl.clear(); + await saveStyle(style, 'config'); +} + +//#endregion +//#region Implementation + +/** @returns {StyleMapData|void} */ +function id2data(id) { + return dataMap.get(id); +} + +/** @returns {StyleObj|void} */ +export function id2style(id) { + return (dataMap.get(Number(id)) || {}).style; +} + +/** @returns {StyleObj|void} */ +export function uuid2style(uuid) { + return id2style(uuidIndex.get(uuid)); +} + +function calcRemoteId({md5Url, updateUrl, [UCD]: ucd} = {}) { + let id; + id = (id = /\d+/.test(md5Url) || URLS.extractUsoaId(updateUrl)) && `uso-${id}` + || (id = URLS.extractUswId(updateUrl)) && `usw-${id}` + || ''; + return id && [ + id, + ucd && !isEmptyObj(ucd.vars), + ]; +} + +/** @returns {StyleObj} */ +function createNewStyle() { + return { + enabled: true, + installDate: Date.now(), + }; +} - function beforeSave(style) { - if (!style.name) { - throw new Error('Style name is empty'); - } - if (!style._id) { - style._id = uuidv4(); - } - if (!style.id) { - delete style.id; - } - style._rev = Date.now(); - fixKnownProblems(style); - } - - /** @returns {Promise} */ - async function saveStyle(style, reason) { - beforeSave(style); - const newId = await db.styles.put(style); - return handleSave(style, reason, newId); - } - - /** - * @param {StyleObj} style - * @param {string|false} [reason] - false = no broadcast - * @param {number} [id] - * @returns {StyleObj} - */ - function handleSave(style, reason, id = style.id) { - if (style.id == null) style.id = id; - const data = id2data(id); - if (!data) { - storeInMap(style); +/** @returns {void} */ +function storeInMap(style) { + dataMap.set(style.id, { + style, + appliesTo: new Set(), + }); + uuidIndex.set(style._id, style.id); +} + +/** @returns {StyleObj} */ +function mergeWithMapped(style) { + return Object.assign({}, + id2style(style.id) || createNewStyle(), + style); +} + +function onDraftEnd(port) { + const id = port.name.split(':')[1]; + API.drafts.delete(+id || id).catch(() => {}); +} + +function onPreviewEnd({name}) { + const id = +name.split(':')[1]; + const data = id2data(id); + if (!data) return; + data.preview = null; + broadcastStyleUpdated(data.style, 'editPreviewEnd'); +} + +function buildCacheForStyle(style) { + const {id} = style; + const data = id2data(id); + // FIXME: ideally, when preview is available, there is no need to rebuild the cache when original style change. + // we should lift this logic to parent function. + const styleToApply = data.preview || style; + const excluded = new Set(); + const updated = new Set(); + for (const [url, cache] of cachedStyleForUrl.entries()) { + if (!data.appliesTo.has(url)) { + cache.maybeMatch.add(id); + continue; + } + const code = getAppliedCode(new MatchQuery(url), styleToApply); + if (code) { + updated.add(url); + buildCacheEntry(cache, styleToApply, code); } else { - data.style = style; - } - if (reason !== 'sync') { - API.sync.putDoc(style); + excluded.add(url); + delete cache.sections[id]; } - if (reason !== false) broadcastStyleUpdated(style, reason, !data); - return style; } + data.appliesTo = updated; +} - // get styles matching a URL, including sloppy regexps and excluded items. - function getAppliedCode(query, data) { - const result = urlMatchStyle(query, data); - if (result === 'included') { - // return all sections - return data.sections.map(s => s.code); - } - if (result !== true) { - return; - } - const code = []; - for (const section of data.sections) { - if (urlMatchSection(query, section) === true && !styleCodeEmpty(section)) { - code.push(section.code); - } - } - return code.length && code; - } - - async function init() { - const [order, styles = []] = await Promise.all([ - API.prefsDb.get(orderWrap.id), - db.styles.getAll(), - prefs.ready, - ]); - const updated = await Promise.all(styles.map(fixKnownProblems).filter(Boolean)); - if (updated.length) setTimeout(db.styles.putMany, 0, updated); - setOrder(order, {store: false}); - styles.forEach(storeInMap); - bgReady._resolveStyles(); - } - - function fixKnownProblems(style, initIndex, initArray) { - if (!style || !style.id) style = {id: Date.now()}; - let res = 0; - for (const key in MISSING_PROPS) { - if (!style[key]) { - style[key] = MISSING_PROPS[key](style); - res = 1; - } - } - /* delete if value is null, {}, [] */ - for (const key in style) { - const v = style[key]; - if (v == null || typeof v === 'object' && isEmptyObj(v)) { - delete style[key]; - res = 1; - } - } - /* Upgrade the old way of customizing local names */ - const {originalName} = style; - if (originalName) { - if (originalName !== style.name) { - style.customName = style.name; - style.name = originalName; - } - delete style.originalName; +function broadcastStyleUpdated(style, reason, isNew) { + buildCacheForStyle(style); + return broadcast({ + method: isNew ? 'styleAdded' : 'styleUpdated', + reason, + style: { + id: style.id, + enabled: style.enabled, + }, + }, {onlyIfStyled: !style.enabled}); +} + +function beforeSave(style) { + if (!style.name) { + throw new Error('Style name is empty'); + } + if (!style._id) { + style._id = uuidv4(); + } + if (!style.id) { + delete style.id; + } + style._rev = Date.now(); + fixKnownProblems(style); +} + +export {saveStyle as save}; + +/** @returns {Promise} */ +export async function saveStyle(style, reason) { + beforeSave(style); + const newId = await db.styles.put(style); + return handleSave(style, reason, newId); +} + +/** + * @param {StyleObj} style + * @param {string|false} [reason] - false = no broadcast + * @param {number} [id] + * @returns {StyleObj} + */ +export function handleSave(style, reason, id = style.id) { + if (style.id == null) style.id = id; + const data = id2data(id); + if (!data) { + storeInMap(style); + } else { + data.style = style; + } + if (reason !== 'sync') { + API.sync.putDoc(style); + } + if (reason !== false) broadcastStyleUpdated(style, reason, !data); + return style; +} + +// get styles matching a URL, including sloppy regexps and excluded items. +function getAppliedCode(query, data) { + const result = urlMatchStyle(query, data); + if (result === 'included') { + // return all sections + return data.sections.map(s => s.code); + } + if (result !== true) { + return; + } + const code = []; + for (const section of data.sections) { + if (urlMatchSection(query, section) === true && !styleCodeEmpty(section)) { + code.push(section.code); + } + } + return code.length && code; +} + +async function init() { + const [order, styles = []] = await Promise.all([ + API.prefsDb.get(orderWrap.id), + db.styles.getAll(), + prefs.ready, + ]); + const updated = await Promise.all(styles.map(fixKnownProblems).filter(Boolean)); + if (updated.length) setTimeout(db.styles.putMany, 0, updated); + setOrderImpl(order, {store: false}); + styles.forEach(storeInMap); + bgReady._resolveStyles(); +} + +function fixKnownProblems(style, initIndex, initArray) { + if (!style || !style.id) style = {id: Date.now()}; + let res = 0; + for (const key in MISSING_PROPS) { + if (!style[key]) { + style[key] = MISSING_PROPS[key](style); res = 1; } - /* wrong homepage url in 1.5.20-1.5.21 due to commit 1e5f118d */ - for (const key of ['url', 'installationUrl']) { - const url = style[key]; - const fixedUrl = url && url.replace(/([^:]\/)\//, '$1'); - if (fixedUrl !== url) { - res = 1; - style[key] = fixedUrl; - } - } - let v; - /* USO bug, duplicate "update" subdomain, see #523 */ - if ((v = style.md5Url) && v.includes('update.update.userstyles')) { - res = style.md5Url = v.replace('update.update.userstyles', 'update.userstyles'); - } - /* Outdated USO-archive links */ - if (`${style.url}${style.installationUrl}`.includes('https://33kk.github.io/uso-archive/')) { - delete style.url; - delete style.installationUrl; - } - /* Default homepage URL for external styles installed from a known distro */ - if ( - (!style.url || !style.installationUrl) && - (v = style.updateUrl) && - (v = URLS.makeInstallUrl(v) || - (v = /\d+/.exec(style.md5Url)) && `${URLS.uso}styles/${v[0]}` - ) - ) { - if (!style.url) res = style.url = v; - if (!style.installationUrl) res = style.installationUrl = v; - } - if (initArray && ( - !Array.isArray(v = style.sections) && (v = 0, true) || - /* @import must precede `vars` that we add at beginning */ - !isEmptyObj((style[UCD] || {}).vars) && v.some(hasVarsAndImport) - )) { - if (!v && !style.sourceCode) { - style.customName = 'Damaged style #' + (style.id || initIndex); - style.sections = [{code: '/* No sections or sourceCode */'}]; - return style; - } - return usercssMan.buildCode(style); - } - return res && style; } - - function hasVarsAndImport({code}) { - return code.startsWith(':root {\n --') && /@import\s/i.test(code); - } - - function urlMatchExclusion(e) { - return compileExclusion(e).test(this.urlWithoutParams); - } - - function urlMatchStyle(query, style) { - let ovr; - if ((ovr = style.exclusions) && ovr.some(urlMatchExclusion, query)) { - return 'excluded'; - } - if (!style.enabled) { - return 'disabled'; - } - if (!colorScheme.shouldIncludeStyle(style)) { - return 'excludedScheme'; + /* delete if value is null, {}, [] */ + for (const key in style) { + const v = style[key]; + if (v == null || typeof v === 'object' && isEmptyObj(v)) { + delete style[key]; + res = 1; } - if ((ovr = style.inclusions) && ovr.some(urlMatchExclusion, query)) { - return 'included'; + } + /* Upgrade the old way of customizing local names */ + const {originalName} = style; + if (originalName) { + if (originalName !== style.name) { + style.customName = style.name; + style.name = originalName; } + delete style.originalName; + res = 1; + } + /* wrong homepage url in 1.5.20-1.5.21 due to commit 1e5f118d */ + for (const key of ['url', 'installationUrl']) { + const url = style[key]; + const fixedUrl = url && url.replace(/([^:]\/)\//, '$1'); + if (fixedUrl !== url) { + res = 1; + style[key] = fixedUrl; + } + } + let v; + /* USO bug, duplicate "update" subdomain, see #523 */ + if ((v = style.md5Url) && v.includes('update.update.userstyles')) { + res = style.md5Url = v.replace('update.update.userstyles', 'update.userstyles'); + } + /* Outdated USO-archive links */ + if (`${style.url}${style.installationUrl}`.includes('https://33kk.github.io/uso-archive/')) { + delete style.url; + delete style.installationUrl; + } + /* Default homepage URL for external styles installed from a known distro */ + if ( + (!style.url || !style.installationUrl) && + (v = style.updateUrl) && + (v = URLS.makeInstallUrl(v) || + (v = /\d+/.exec(style.md5Url)) && `${URLS.uso}styles/${v[0]}` + ) + ) { + if (!style.url) res = style.url = v; + if (!style.installationUrl) res = style.installationUrl = v; + } + if (initArray && ( + !Array.isArray(v = style.sections) && (v = 0, true) || + /* @import must precede `vars` that we add at beginning */ + !isEmptyObj((style[UCD] || {}).vars) && v.some(hasVarsAndImport) + )) { + if (!v && !style.sourceCode) { + style.customName = 'Damaged style #' + (style.id || initIndex); + style.sections = [{code: '/* No sections or sourceCode */'}]; + return style; + } + return API.usercss.buildCode(style); + } + return res && style; +} + +function hasVarsAndImport({code}) { + return code.startsWith(':root {\n --') && /@import\s/i.test(code); +} + +function urlMatchExclusion(e) { + return compileExclusion(e).test(this.urlWithoutParams); +} + +function urlMatchStyle(query, style) { + let ovr; + if ((ovr = style.exclusions) && ovr.some(urlMatchExclusion, query)) { + return 'excluded'; + } + if (!style.enabled) { + return 'disabled'; + } + if (!colorScheme.shouldIncludeStyle(style)) { + return 'excludedScheme'; + } + if ((ovr = style.inclusions) && ovr.some(urlMatchExclusion, query)) { + return 'included'; + } + return true; +} + +function urlMatchSection(query, section, skipEmptyGlobal) { + let dd, ddL, pp, ppL, rr, rrL, uu, uuL; + if ( + (dd = section.domains) && (ddL = dd.length) && dd.some(urlMatchDomain, query) || + (pp = section.urlPrefixes) && (ppL = pp.length) && pp.some(urlMatchPrefix, query) || + /* Per the specification the fragment portion is ignored in @-moz-document: + https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#url-of-doc + but the spec is outdated and doesn't account for SPA sites, + so we only respect it for `url()` function */ + (uu = section.urls) && (uuL = uu.length) && ( + uu.includes(query.url) || + uu.includes(query.urlWithoutHash) + ) || + (rr = section.regexps) && (rrL = rr.length) && rr.some(urlMatchRegexp, query) + ) { return true; } - - function urlMatchSection(query, section, skipEmptyGlobal) { - let dd, ddL, pp, ppL, rr, rrL, uu, uuL; - if ( - (dd = section.domains) && (ddL = dd.length) && dd.some(urlMatchDomain, query) || - (pp = section.urlPrefixes) && (ppL = pp.length) && pp.some(urlMatchPrefix, query) || - /* Per the specification the fragment portion is ignored in @-moz-document: - https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#url-of-doc - but the spec is outdated and doesn't account for SPA sites, - so we only respect it for `url()` function */ - (uu = section.urls) && (uuL = uu.length) && ( - uu.includes(query.url) || - uu.includes(query.urlWithoutHash) - ) || - (rr = section.regexps) && (rrL = rr.length) && rr.some(urlMatchRegexp, query) - ) { - return true; - } - /* - According to CSS4 @document specification the entire URL must match. - Stylish-for-Chrome implemented it incorrectly since the very beginning. - We'll detect styles that abuse the bug by finding the sections that - would have been applied by Stylish but not by us as we follow the spec. - */ - if (rrL && rr.some(urlMatchRegexpSloppy, query)) { - return 'sloppy'; - } - // TODO: check for invalid regexps? - return !rrL && !ppL && !uuL && !ddL && - !query.isOwnPage && // We allow only intentionally targeted sections for own pages - (!skipEmptyGlobal || !styleCodeEmpty(section)); - } - /** @this {MatchQuery} */ - function urlMatchDomain(d) { - const _d = this.domain; - return d === _d || - _d[_d.length - d.length - 1] === '.' && _d.endsWith(d); - } - /** @this {MatchQuery} */ - function urlMatchPrefix(p) { - return p && this.url.startsWith(p); - } - /** @this {MatchQuery} */ - function urlMatchRegexp(r) { - return (!this.isOwnPage || /\bextension\b/.test(r)) && - compileRe(r).test(this.url); - } - /** @this {MatchQuery} */ - function urlMatchRegexpSloppy(r) { - return (!this.isOwnPage || /\bextension\b/.test(r)) && - compileSloppyRe(r).test(this.url); - } - - function createCompiler(compile) { - // FIXME: FIFO cache doesn't work well here, if we want to match many - // regexps more than the cache size, we will never hit the cache because - // the first cache is deleted. So we use a simple map but it leaks memory. - const cache = new Map(); - return text => { - let re = cache.get(text); + /* + According to CSS4 @document specification the entire URL must match. + Stylish-for-Chrome implemented it incorrectly since the very beginning. + We'll detect styles that abuse the bug by finding the sections that + would have been applied by Stylish but not by us as we follow the spec. + */ + if (rrL && rr.some(urlMatchRegexpSloppy, query)) { + return 'sloppy'; + } + // TODO: check for invalid regexps? + return !rrL && !ppL && !uuL && !ddL && + !query.isOwnPage && // We allow only intentionally targeted sections for own pages + (!skipEmptyGlobal || !styleCodeEmpty(section)); +} +/** @this {MatchQuery} */ +function urlMatchDomain(d) { + const _d = this.domain; + return d === _d || + _d[_d.length - d.length - 1] === '.' && _d.endsWith(d); +} +/** @this {MatchQuery} */ +function urlMatchPrefix(p) { + return p && this.url.startsWith(p); +} +/** @this {MatchQuery} */ +function urlMatchRegexp(r) { + return (!this.isOwnPage || /\bextension\b/.test(r)) && + compileRe(r).test(this.url); +} +/** @this {MatchQuery} */ +function urlMatchRegexpSloppy(r) { + return (!this.isOwnPage || /\bextension\b/.test(r)) && + compileSloppyRe(r).test(this.url); +} + +function createCompiler(compile) { + // FIXME: FIFO cache doesn't work well here, if we want to match many + // regexps more than the cache size, we will never hit the cache because + // the first cache is deleted. So we use a simple map but it leaks memory. + const cache = new Map(); + return text => { + let re = cache.get(text); + if (!re) { + re = tryRegExp(compile(text)); if (!re) { - re = tryRegExp(compile(text)); - if (!re) { - re = BAD_MATCHER; - } - cache.set(text, re); + re = BAD_MATCHER; } - return re; - }; - } - - function compileGlob(text) { - return stringAsRegExpStr(text) - .replace(/\\\\\\\*|\\\*/g, m => m.length > 2 ? m : '.*'); - } - - function buildExclusion(text) { - // match pattern - const match = text.match(/^(\*|[\w-]+):\/\/(\*\.)?([\w.]+\/.*)/); - if (!match) { - return '^' + compileGlob(text) + '$'; + cache.set(text, re); } - return '^' + - (match[1] === '*' ? '[\\w-]+' : match[1]) + - '://' + - (match[2] ? '(?:[\\w.]+\\.)?' : '') + - compileGlob(match[3]) + - '$'; - } - - function buildCache(cache, url, styleList) { - const query = new MatchQuery(url); - for (const {style, appliesTo, preview} of styleList) { - // getSectionsByUrl only needs enabled styles - const code = style.enabled && getAppliedCode(query, preview || style); - if (code) { - buildCacheEntry(cache, style, code); - appliesTo.add(url); - } + return re; + }; +} + +function compileGlob(text) { + return stringAsRegExpStr(text) + .replace(/\\\\\\\*|\\\*/g, m => m.length > 2 ? m : '.*'); +} + +function buildExclusion(text) { + // match pattern + const match = text.match(/^(\*|[\w-]+):\/\/(\*\.)?([\w.]+\/.*)/); + if (!match) { + return '^' + compileGlob(text) + '$'; + } + return '^' + + (match[1] === '*' ? '[\\w-]+' : match[1]) + + '://' + + (match[2] ? '(?:[\\w.]+\\.)?' : '') + + compileGlob(match[3]) + + '$'; +} + +function buildCache(cache, url, styleList) { + const query = new MatchQuery(url); + for (const {style, appliesTo, preview} of styleList) { + // getSectionsByUrl only needs enabled styles + const code = style.enabled && getAppliedCode(query, preview || style); + if (code) { + buildCacheEntry(cache, style, code); + appliesTo.add(url); + } + } +} + +function buildCacheEntry(cache, style, code = style.code) { + /** @type {InjectedStyle} */ + cache.sections[style.id] = { + code, + id: style.id, + name: style.customName || style.name, + }; +} + +/** @return {Generator} */ +export function *iterStyles() { + for (const v of dataMap.values()) yield v.style; +} + +/** uuidv4 helper: converts to a 4-digit hex string and adds "-" at required positions */ +function hex4dashed(num, i) { + return (num + 0x10000).toString(16).slice(-4) + (i >= 1 && i <= 4 ? '-' : ''); +} + +async function setOrderImpl(data, {broadcast, calc = true, store = true, sync} = {}) { + if (!data || !data.value || deepEqual(data.value, orderWrap.value)) { + return; + } + Object.assign(orderWrap, data, sync && {_rev: Date.now()}); + if (calc) { + for (const [type, group] of Object.entries(data.value)) { + const dst = order[type] = {}; + group.forEach((uuid, i) => { + const id = uuidIndex.get(uuid); + if (id) dst[id] = i; + }); } } - - function buildCacheEntry(cache, style, code = style.code) { - /** @type {InjectedStyle} */ - cache.sections[style.id] = { - code, - id: style.id, - name: style.customName || style.name, - }; + if (broadcast) { + broadcastInjectorConfig('order', order); } - - /** @return {Generator} */ - function *iterStyles() { - for (const v of dataMap.values()) yield v.style; + if (store) { + await API.prefsDb.put(orderWrap, orderWrap.id); } - - /** uuidv4 helper: converts to a 4-digit hex string and adds "-" at required positions */ - function hex4dashed(num, i) { - return (num + 0x10000).toString(16).slice(-4) + (i >= 1 && i <= 4 ? '-' : ''); + if (sync) { + API.sync.putDoc(orderWrap); } +} - async function setOrder(data, {broadcast, calc = true, store = true, sync} = {}) { - if (!data || !data.value || deepEqual(data.value, orderWrap.value)) { - return; - } - Object.assign(orderWrap, data, sync && {_rev: Date.now()}); - if (calc) { - for (const [type, group] of Object.entries(data.value)) { - const dst = order[type] = {}; - group.forEach((uuid, i) => { - const id = uuidIndex.get(uuid); - if (id) dst[id] = i; - }); - } - } - if (broadcast) { - broadcastInjectorConfig('order', order); - } - if (store) { - await API.prefsDb.put(orderWrap, orderWrap.id); - } - if (sync) { - API.sync.putDoc(orderWrap); - } - } +//#endregion - //#endregion -})(); +export { + id2style as get, +}; diff --git a/src/background/style-search-db.js b/src/background/style-search-db.js index 6395cdde982..54461c82cbe 100644 --- a/src/background/style-search-db.js +++ b/src/background/style-search-db.js @@ -1,110 +1,106 @@ -/* global RX_META UCD debounce stringAsRegExp tryRegExp */// toolbox.js -/* global addAPI */// common.js -/* global styleMan */ -/* global styleUtil */ -'use strict'; +import {RX_META, UCD, debounce, stringAsRegExp, tryRegExp} from '/js/toolbox'; +import {addAPI} from './common'; +import {getByUrl, iterStyles} from './style-manager'; -(() => { - // toLocaleLowerCase cache, autocleared after 1 minute - const cache = new Map(); - const METAKEYS = ['customName', 'name', 'url', 'installationUrl', 'updateUrl']; +// toLocaleLowerCase cache, autocleared after 1 minute +const cache = new Map(); +const METAKEYS = ['customName', 'name', 'url', 'installationUrl', 'updateUrl']; - const extractMeta = style => - style[UCD] - ? (style.sourceCode.match(RX_META) || [''])[0] - : null; +const extractMeta = style => + style[UCD] + ? (style.sourceCode.match(RX_META) || [''])[0] + : null; - const stripMeta = style => - style[UCD] - ? style.sourceCode.replace(RX_META, '') - : null; +const stripMeta = style => + style[UCD] + ? style.sourceCode.replace(RX_META, '') + : null; - const MODES = Object.assign(Object.create(null), { - code: (style, test) => - style[UCD] - ? test(stripMeta(style)) - : searchSections(style, test, 'code'), +const MODES = Object.assign(Object.create(null), { + code: (style, test) => + style[UCD] + ? test(stripMeta(style)) + : searchSections(style, test, 'code'), - meta: (style, test, part) => - METAKEYS.some(key => test(style[key])) || - test(part === 'all' ? style.sourceCode : extractMeta(style)) || - searchSections(style, test, 'funcs'), + meta: (style, test, part) => + METAKEYS.some(key => test(style[key])) || + test(part === 'all' ? style.sourceCode : extractMeta(style)) || + searchSections(style, test, 'funcs'), - name: (style, test) => - test(style.customName) || - test(style.name), + name: (style, test) => + test(style.customName) || + test(style.name), - all: (style, test) => - MODES.meta(style, test, 'all') || - !style[UCD] && MODES.code(style, test), - }); + all: (style, test) => + MODES.meta(style, test, 'all') || + !style[UCD] && MODES.code(style, test), +}); - addAPI(/** @namespace API */ { - styles: { - /** - * @param params - * @param {string} params.query - 1. url:someurl 2. text (may contain quoted parts like "qUot Ed") - * @param {'name'|'meta'|'code'|'all'|'url'} [params.mode=all] - * @param {number[]} [params.ids] - if not specified, all styles are searched - * @returns {number[]} - array of matched styles ids - */ - searchDB({query, mode = 'all', ids}) { - let res = []; - if (mode === 'url' && query) { - res = styleMan.getByUrl(query).map(r => r.style.id); - } else if (mode in MODES) { - const modeHandler = MODES[mode]; - const m = /^\/(.+?)\/([gimsuy]*)$/.exec(query); - const rx = m && tryRegExp(m[1], m[2]); - const test = rx ? rx.test.bind(rx) : createTester(query); - for (const style of styleUtil.iterStyles()) { - if ((!ids || ids.includes(style.id)) && - (!query || modeHandler(style, test))) { - res.push(style.id); - } +addAPI(/** @namespace API */ { + styles: { + /** + * @param params + * @param {string} params.query - 1. url:someurl 2. text (may contain quoted parts like "qUot Ed") + * @param {'name'|'meta'|'code'|'all'|'url'} [params.mode=all] + * @param {number[]} [params.ids] - if not specified, all styles are searched + * @returns {number[]} - array of matched styles ids + */ + searchDB({query, mode = 'all', ids}) { + let res = []; + if (mode === 'url' && query) { + res = getByUrl(query).map(r => r.style.id); + } else if (mode in MODES) { + const modeHandler = MODES[mode]; + const m = /^\/(.+?)\/([gimsuy]*)$/.exec(query); + const rx = m && tryRegExp(m[1], m[2]); + const test = rx ? rx.test.bind(rx) : createTester(query); + for (const style of iterStyles()) { + if ((!ids || ids.includes(style.id)) && + (!query || modeHandler(style, test))) { + res.push(style.id); } - if (cache.size) debounce(clearCache, 60e3); } - return res; - }, + if (cache.size) debounce(clearCache, 60e3); + } + return res; }, - }); + }, +}); - function createTester(query) { - const flags = `u${lower(query) === query ? 'i' : ''}`; - const words = query - .split(/(".*?")|\s+/) - .filter(Boolean) - .map(w => w.startsWith('"') && w.endsWith('"') - ? w.slice(1, -1) - : w) - .filter(w => w.length > 1); - const rxs = (words.length ? words : [query]) - .map(w => stringAsRegExp(w, flags)); - return text => rxs.every(rx => rx.test(text)); - } +function createTester(query) { + const flags = `u${lower(query) === query ? 'i' : ''}`; + const words = query + .split(/(".*?")|\s+/) + .filter(Boolean) + .map(w => w.startsWith('"') && w.endsWith('"') + ? w.slice(1, -1) + : w) + .filter(w => w.length > 1); + const rxs = (words.length ? words : [query]) + .map(w => stringAsRegExp(w, flags)); + return text => rxs.every(rx => rx.test(text)); +} - function searchSections({sections}, test, part) { - const inCode = part === 'code' || part === 'all'; - const inFuncs = part === 'funcs' || part === 'all'; - for (const section of sections) { - for (const prop in section) { - const value = section[prop]; - if (inCode && prop === 'code' && test(value) || - inFuncs && Array.isArray(value) && value.some(str => test(str))) { - return true; - } +function searchSections({sections}, test, part) { + const inCode = part === 'code' || part === 'all'; + const inFuncs = part === 'funcs' || part === 'all'; + for (const section of sections) { + for (const prop in section) { + const value = section[prop]; + if (inCode && prop === 'code' && test(value) || + inFuncs && Array.isArray(value) && value.some(str => test(str))) { + return true; } } } +} - function lower(text) { - let result = cache.get(text); - if (!result) cache.set(text, result = text.toLocaleLowerCase()); - return result; - } +function lower(text) { + let result = cache.get(text); + if (!result) cache.set(text, result = text.toLocaleLowerCase()); + return result; +} - function clearCache() { - cache.clear(); - } -})(); +function clearCache() { + cache.clear(); +} diff --git a/src/background/style-via-api.js b/src/background/style-via-api.js index 817b8568ea5..1a8325754db 100644 --- a/src/background/style-via-api.js +++ b/src/background/style-via-api.js @@ -1,15 +1,14 @@ -/* global API */// msg.js -/* global addAPI */// common.js -/* global isEmptyObj */// toolbox.js -/* global prefs */ -/* global styleMan styleUtil */// style-manager.js -'use strict'; +import browser from '/js/browser'; +import * as prefs from '/js/prefs'; +import {isEmptyObj} from '/js/toolbox'; +import {addAPI, API} from './common'; +import {getSectionsByUrl, order} from './style-manager'; /** * Uses chrome.tabs.insertCSS */ -(() => { +if (FIREFOX) (() => { // eslint-disable-line curly const ACTIONS = { styleApply, styleDeleted, @@ -56,8 +55,7 @@ if (id === null && !ignoreUrlCheck && frameStyles.url === url) { return; } - const {sections} = styleMan.getSectionsByUrl(url, id); - const {order} = styleUtil; + const {sections} = getSectionsByUrl(url, id); const tasks = []; const calcOrder = ({id}) => (order.prio[id] || 0) * 1e6 || diff --git a/src/background/style-via-webrequest.js b/src/background/style-via-webrequest.js index ad1cc059aa2..6ae1ec336d3 100644 --- a/src/background/style-via-webrequest.js +++ b/src/background/style-via-webrequest.js @@ -1,186 +1,185 @@ -/* global API msg */// msg.js -/* global CHROME FIREFOX URLS ignoreChromeError */// toolbox.js -/* global prefs */ -/* global popupGetStyles */ -/* global styleMan */ -/* global tabMan */ -'use strict'; +import popupGetStyles from '/js/popup-get-styles'; +import * as prefs from '/js/prefs'; +import {ignoreChromeError, URLS} from '/js/toolbox'; +import {API, bgReady} from './common'; +import {getSectionsByUrl} from './style-manager'; +import tabMan from './tab-manager'; -(() => { - const idCSP = 'patchCsp'; - const idOFF = 'disableAll'; - const idXHR = 'styleViaXhr'; - const rxHOST = /^('non(e|ce-.+?)'|(https?:\/\/)?[^']+?[^:'])$/; // strips CSP sources covered by * - const rxNONCE = FIREFOX && /(?:^|[;,])\s*style-src\s+[^;,]*?'nonce-([-+/=\w]+)'/; - const blobUrlPrefix = 'blob:' + chrome.runtime.getURL('/'); - /** @type {Object} */ - const stylesToPass = {}; - const state = {}; - const injectedCode = `${data => { - if (self.INJECTED !== 1) { // storing data only if apply.js hasn't run yet - window[Symbol.for('styles')] = data; - } - }}`; +const idCSP = 'patchCsp'; +const idOFF = 'disableAll'; +const idXHR = 'styleViaXhr'; +const rxHOST = /^('non(e|ce-.+?)'|(https?:\/\/)?[^']+?[^:'])$/; // strips CSP sources covered by * +const rxNONCE = FIREFOX && /(?:^|[;,])\s*style-src\s+[^;,]*?'nonce-([-+/=\w]+)'/; +const blobUrlPrefix = 'blob:' + chrome.runtime.getURL('/'); +/** @type {Object} */ +const stylesToPass = {}; +const state = {}; +const injectedCode = `${data => { + if (self.INJECTED !== 1) { // storing data only if apply.js hasn't run yet + window[Symbol.for('styles')] = data; + } +}}`; - toggle(); - prefs.subscribe([idXHR, idOFF, idCSP], toggle); +toggle(); +prefs.subscribe([idXHR, idOFF, idCSP], toggle); - function toggle() { - const off = prefs.get(idOFF); - const csp = prefs.get(idCSP) && !off; - const xhr = prefs.get(idXHR) && !off; - if (xhr === state.xhr && csp === state.csp && off === state.off) { - return; - } - const reqFilter = { - urls: [ - '*://*/*', - CHROME && chrome.runtime.getURL(chrome.runtime.getManifest().browser_action.default_popup), - ].filter(Boolean), - types: ['main_frame', 'sub_frame'], - }; - chrome.webNavigation.onCommitted.removeListener(injectData); - chrome.webRequest.onBeforeRequest.removeListener(prepareStyles); - chrome.webRequest.onHeadersReceived.removeListener(modifyHeaders); - if (xhr || csp || FIREFOX) { - // We unregistered it above so that the optional EXTRA_HEADERS is properly re-registered - chrome.webRequest.onHeadersReceived.addListener(modifyHeaders, reqFilter, [ - 'blocking', - 'responseHeaders', - xhr && chrome.webRequest.OnHeadersReceivedOptions.EXTRA_HEADERS, - ].filter(Boolean)); - } - if (!off) { - chrome.webRequest.onBeforeRequest.addListener(prepareStyles, reqFilter); - } - if (CHROME && !off) { - chrome.webNavigation.onCommitted.addListener(injectData, {url: [{urlPrefix: 'http'}]}); - } - if (CHROME) { - chrome.webRequest.onBeforeRequest.addListener(openNamedStyle, { - urls: [URLS.ownOrigin + '*.user.css'], - types: ['main_frame'], - }, ['blocking']); - } - state.csp = csp; - state.off = off; - state.xhr = xhr; +function toggle() { + const off = prefs.get(idOFF); + const csp = prefs.get(idCSP) && !off; + const xhr = prefs.get(idXHR) && !off; + if (xhr === state.xhr && csp === state.csp && off === state.off) { + return; } - - /** @param {chrome.webRequest.WebRequestBodyDetails} req */ - function prepareStyles(req) { - if (!msg.ready) return; - if (req.url.startsWith(URLS.ownOrigin)) return preloadPopupData(); - const {url} = req; - req.tab = {url}; - stylesToPass[req2key(req)] = /** @namespace StylesToPass */ { - blobId: '', - payload: styleMan.getSectionsByUrl.call({sender: req}, url, null, true), - timer: setTimeout(cleanUp, 600e3, req), - }; + const reqFilter = { + urls: [ + '*://*/*', + CHROME && + chrome.runtime.getURL(chrome.runtime.getManifest().browser_action.default_popup), + ].filter(Boolean), + types: ['main_frame', 'sub_frame'], + }; + chrome.webNavigation.onCommitted.removeListener(injectData); + chrome.webRequest.onBeforeRequest.removeListener(prepareStyles); + chrome.webRequest.onHeadersReceived.removeListener(modifyHeaders); + if (xhr || csp || FIREFOX) { + // We unregistered it above so that the optional EXTRA_HEADERS is properly re-registered + chrome.webRequest.onHeadersReceived.addListener(modifyHeaders, reqFilter, [ + 'blocking', + 'responseHeaders', + xhr && chrome.webRequest.OnHeadersReceivedOptions.EXTRA_HEADERS, + ].filter(Boolean)); } - - function injectData(req) { - const data = stylesToPass[req2key(req)]; - if (data && !data.injected) { - data.injected = true; - chrome.tabs.executeScript(req.tabId, { - frameId: req.frameId, - runAt: 'document_start', - code: `(${injectedCode})(${JSON.stringify(data.payload)})`, - }, ignoreChromeError); - if (!state.xhr) cleanUp(req); - } + if (!off) { + chrome.webRequest.onBeforeRequest.addListener(prepareStyles, reqFilter); } - - /** @param {chrome.webRequest.WebResponseHeadersDetails} req */ - function modifyHeaders(req) { - const data = stylesToPass[req2key(req)]; if (!data) return; - const {responseHeaders} = req; - const {payload} = data; - const secs = payload.sections; - const csp = (FIREFOX || state.csp) && - responseHeaders.find(h => h.name.toLowerCase() === 'content-security-policy'); - if (csp) { - const m = FIREFOX && csp.value.match(rxNONCE); - if (m) tabMan.set(req.tabId, 'nonce', req.frameId, payload.cfg.nonce = m[1]); - // We don't change CSP if there are no styles when the page is loaded - // TODO: show a reminder in the popup to reload the tab when the user enables a style - if (state.csp && secs[0]) patchCsp(csp); - } - if (!secs[0]) { - cleanUp(req); - return; - } - if (state.xhr) { - data.blobId = URL.createObjectURL(new Blob([JSON.stringify(payload)])).slice(blobUrlPrefix.length); - responseHeaders.push({ - name: 'Set-Cookie', - value: `${chrome.runtime.id}=${data.blobId}; SameSite=Lax`, - }); - } - if (state.xhr || csp && state.csp) { - return {responseHeaders}; - } + if (CHROME && !off) { + chrome.webNavigation.onCommitted.addListener(injectData, {url: [{urlPrefix: 'http'}]}); + } + if (CHROME) { + chrome.webRequest.onBeforeRequest.addListener(openNamedStyle, { + urls: [URLS.ownOrigin + '*.user.css'], + types: ['main_frame'], + }, ['blocking']); } + state.csp = csp; + state.off = off; + state.xhr = xhr; +} - /** @param {chrome.webRequest.HttpHeader} csp */ - function patchCsp(csp) { - const src = {}; - for (let p of csp.value.split(/[;,]/)) { - p = p.trim().split(/\s+/); - src[p[0]] = p.slice(1); - } - // Allow style assets - patchCspSrc(src, 'img-src', 'data:', '*'); - patchCspSrc(src, 'font-src', 'data:', '*'); - // Allow our DOM styles, allow @import from any URL - patchCspSrc(src, 'style-src', "'unsafe-inline'", '*'); - // Allow our XHR cookies in CSP sandbox (known case: raw github urls) - if (src.sandbox && !src.sandbox.includes('allow-same-origin')) { - src.sandbox.push('allow-same-origin'); - } - csp.value = Object.entries(src).map(([k, v]) => - `${k}${v.length ? ' ' : ''}${v.join(' ')}`).join('; '); +/** @param {chrome.webRequest.WebRequestBodyDetails} req */ +function prepareStyles(req) { + if (!self.msg) return; + if (req.url.startsWith(URLS.ownOrigin)) return preloadPopupData(); + const {url} = req; + req.tab = {url}; + stylesToPass[req2key(req)] = /** @namespace StylesToPass */ { + blobId: '', + payload: getSectionsByUrl.call({sender: req}, url, null, true), + timer: setTimeout(cleanUp, 600e3, req), + }; +} + +function injectData(req) { + const data = stylesToPass[req2key(req)]; + if (data && !data.injected) { + data.injected = true; + chrome.tabs.executeScript(req.tabId, { + frameId: req.frameId, + runAt: 'document_start', + code: `(${injectedCode})(${JSON.stringify(data.payload)})`, + }, ignoreChromeError); + if (!state.xhr) cleanUp(req); } +} - function patchCspSrc(src, name, ...values) { - let def = src['default-src']; - let list = src[name]; - if (def || list) { - if (!def) def = []; - if (!list) list = [...def]; - if (values.includes('*')) list = src[name] = list.filter(v => !rxHOST.test(v)); - list.push(...values.filter(v => !list.includes(v))); - if (!list.length) delete src[name]; - } +/** @param {chrome.webRequest.WebResponseHeadersDetails} req */ +function modifyHeaders(req) { + const data = stylesToPass[req2key(req)]; if (!data) return; + const {responseHeaders} = req; + const {payload} = data; + const secs = payload.sections; + const csp = (FIREFOX || state.csp) && + responseHeaders.find(h => h.name.toLowerCase() === 'content-security-policy'); + if (csp) { + const m = FIREFOX && csp.value.match(rxNONCE); + if (m) tabMan.set(req.tabId, 'nonce', req.frameId, payload.cfg.nonce = m[1]); + // We don't change CSP if there are no styles when the page is loaded + // TODO: show a reminder in the popup to reload the tab when the user enables a style + if (state.csp && secs[0]) patchCsp(csp); + } + if (!secs[0]) { + cleanUp(req); + return; } + if (state.xhr) { + data.blobId = URL.createObjectURL(new Blob([JSON.stringify(payload)])) + .slice(blobUrlPrefix.length); + responseHeaders.push({ + name: 'Set-Cookie', + value: `${chrome.runtime.id}=${data.blobId}; SameSite=Lax`, + }); + } + if (state.xhr || csp && state.csp) { + return {responseHeaders}; + } +} - async function preloadPopupData() { - API.data.set('popupData', await popupGetStyles()); +/** @param {chrome.webRequest.HttpHeader} csp */ +function patchCsp(csp) { + const src = {}; + for (let p of csp.value.split(/[;,]/)) { + p = p.trim().split(/\s+/); + src[p[0]] = p.slice(1); + } + // Allow style assets + patchCspSrc(src, 'img-src', 'data:', '*'); + patchCspSrc(src, 'font-src', 'data:', '*'); + // Allow our DOM styles, allow @import from any URL + patchCspSrc(src, 'style-src', "'unsafe-inline'", '*'); + // Allow our XHR cookies in CSP sandbox (known case: raw github urls) + if (src.sandbox && !src.sandbox.includes('allow-same-origin')) { + src.sandbox.push('allow-same-origin'); } + csp.value = Object.entries(src).map(([k, v]) => + `${k}${v.length ? ' ' : ''}${v.join(' ')}`).join('; '); +} - function cleanUp(req) { - const key = req2key(req); - const data = stylesToPass[key]; - if (data) { - delete stylesToPass[key]; - clearTimeout(data.timer); - if (data.blobId) { - URL.revokeObjectURL(blobUrlPrefix + data.blobId); - } - } +function patchCspSrc(src, name, ...values) { + let def = src['default-src']; + let list = src[name]; + if (def || list) { + if (!def) def = []; + if (!list) list = [...def]; + if (values.includes('*')) list = src[name] = list.filter(v => !rxHOST.test(v)); + list.push(...values.filter(v => !list.includes(v))); + if (!list.length) delete src[name]; } +} + +async function preloadPopupData() { + API.data.set('popupData', await popupGetStyles()); +} - /** @param {chrome.webRequest.WebRequestBodyDetails} req */ - function openNamedStyle(req) { - if (!req.url.includes('?')) { // skipping our usercss installer - chrome.tabs.update(req.tabId, {url: 'edit.html?id=' + req.url.split('#')[1]}); - return {cancel: true}; +function cleanUp(req) { + const key = req2key(req); + const data = stylesToPass[key]; + if (data) { + delete stylesToPass[key]; + clearTimeout(data.timer); + if (data.blobId) { + URL.revokeObjectURL(blobUrlPrefix + data.blobId); } } +} - function req2key(req) { - return req.tabId + ':' + req.frameId; +/** @param {chrome.webRequest.WebRequestBodyDetails} req */ +function openNamedStyle(req) { + if (!req.url.includes('?')) { // skipping our usercss installer + chrome.tabs.update(req.tabId, {url: 'edit.html?id=' + req.url.split('#')[1]}); + return {cancel: true}; } -})(); +} + +function req2key(req) { + return req.tabId + ':' + req.frameId; +} diff --git a/src/background/sync-manager.js b/src/background/sync-manager.js index 7fa62cfc40b..b79ac0c7b17 100644 --- a/src/background/sync-manager.js +++ b/src/background/sync-manager.js @@ -1,309 +1,305 @@ -/* global msg */// msg.js -/* global bgReady uuidIndex */// common.js -/* global chromeLocal chromeSync */// storage-util.js -/* global db */ -/* global iconMan */ -/* global prefs */ -/* global styleMan */ -/* global styleUtil */ -/* global tokenMan */ -'use strict'; +import browser from '/js/browser'; +import * as prefs from '/js/prefs'; +import {chromeLocal, chromeSync} from '/js/storage-util'; +import {bgPrefsSet} from './bg-prefs'; +import {broadcastExtension} from './broadcast'; +import {bgReady, uuidIndex} from './common'; +import db from './db'; +import {overrideBadge} from './icon-manager'; +import * as styleMan from './style-manager'; +import {getToken, revokeToken} from './token-manager'; -const syncMan = (() => { - //#region Init +//#region Init - const SYNC_DELAY = 1; // minutes - const SYNC_INTERVAL = 30; // minutes - const STATES = Object.freeze({ - connected: 'connected', - connecting: 'connecting', - disconnected: 'disconnected', - disconnecting: 'disconnecting', - }); - const STORAGE_KEY = 'sync/state/'; - const NO_LOGIN = ['webdav']; - const status = /** @namespace SyncManager.Status */ { - STATES, - state: STATES.disconnected, - syncing: false, - progress: null, - currentDriveName: null, - errorMessage: null, - login: false, - }; - const compareRevision = (rev1, rev2) => rev1 - rev2; - let lastError = null; - let ctrl; - let currentDrive; - /** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */ - let ready = bgReady.styles.then(() => { - ready = true; - prefs.subscribe('sync.enabled', - (_, val) => val === 'none' - ? syncMan.stop() - : syncMan.start(val, true), - true); - }); +const SYNC_DELAY = 1; // minutes +const SYNC_INTERVAL = 30; // minutes +const STATES = Object.freeze({ + connected: 'connected', + connecting: 'connecting', + disconnected: 'disconnected', + disconnecting: 'disconnecting', +}); +const STORAGE_KEY = 'sync/state/'; +const NO_LOGIN = ['webdav']; +const status = /** @namespace SyncManager.Status */ { + STATES, + state: STATES.disconnected, + syncing: false, + progress: null, + currentDriveName: null, + errorMessage: null, + login: false, +}; +const compareRevision = (rev1, rev2) => rev1 - rev2; +let lastError = null; +let ctrl; +let currentDrive; +/** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */ +let ready = bgReady.styles.then(() => { + ready = true; + prefs.subscribe('sync.enabled', + (_, val) => val === 'none' + ? stop() + : start(val, true), + true); +}); - chrome.alarms.onAlarm.addListener(async ({name}) => { - if (name === 'syncNow') { - await syncMan.syncNow(); - } - }); +chrome.alarms.onAlarm.addListener(async ({name}) => { + if (name === 'syncNow') { + await syncNow(); + } +}); - //#endregion - //#region Exports +//#endregion +//#region Exports - return { +export async function remove(...args) { + if (ready.then) await ready; + if (!currentDrive) return; + schedule(); + return ctrl.delete(...args); +} - async delete(...args) { - if (ready.then) await ready; - if (!currentDrive) return; - schedule(); - return ctrl.delete(...args); - }, +/** @returns {Promise} */ +export async function getStatus() { + return status; +} - /** @returns {Promise} */ - async getStatus() { - return status; - }, +export async function login(name) { + if (ready.then) await ready; + if (!name) name = prefs.get('sync.enabled'); + await revokeToken(name); + try { + await getToken(name, true); + status.login = true; + } catch (err) { + status.login = false; + throw err; + } finally { + emitStatusChange(); + } +} - async login(name) { - if (ready.then) await ready; - if (!name) name = prefs.get('sync.enabled'); - await tokenMan.revokeToken(name); - try { - await tokenMan.getToken(name, true); - status.login = true; - } catch (err) { - status.login = false; - throw err; - } finally { - emitStatusChange(); - } - }, +export async function putDoc({_id, _rev}) { + if (ready.then) await ready; + if (!currentDrive) return; + schedule(); + return ctrl.put(_id, _rev); +} - async putDoc({_id, _rev}) { - if (ready.then) await ready; - if (!currentDrive) return; - schedule(); - return ctrl.put(_id, _rev); - }, +export async function setDriveOptions(driveName, options) { + const key = `secure/sync/driveOptions/${driveName}`; + await chromeSync.setValue(key, options); +} - async setDriveOptions(driveName, options) { - const key = `secure/sync/driveOptions/${driveName}`; - await chromeSync.setValue(key, options); - }, +export async function getDriveOptions(driveName) { + const key = `secure/sync/driveOptions/${driveName}`; + return await chromeSync.getValue(key) || {}; +} - async getDriveOptions(driveName) { - const key = `secure/sync/driveOptions/${driveName}`; - return await chromeSync.getValue(key) || {}; - }, +export async function start(name, fromPref = false) { + if (ready.then) await ready; + if (!ctrl) await initController(); - async start(name, fromPref = false) { - if (ready.then) await ready; - if (!ctrl) await initController(); + if (currentDrive) return; + currentDrive = await getDrive(name); + ctrl.use(currentDrive); - if (currentDrive) return; - currentDrive = await getDrive(name); - ctrl.use(currentDrive); + status.state = STATES.connecting; + status.currentDriveName = currentDrive.name; + emitStatusChange(); - status.state = STATES.connecting; - status.currentDriveName = currentDrive.name; + if (fromPref || NO_LOGIN.includes(currentDrive.name)) { + status.login = true; + } else { + try { + await login(name); + } catch (err) { + console.error(err); + status.errorMessage = err.message; + lastError = err; emitStatusChange(); + return stop(); + } + } - if (fromPref || NO_LOGIN.includes(currentDrive.name)) { - status.login = true; - } else { - try { - await syncMan.login(name); - } catch (err) { - console.error(err); - status.errorMessage = err.message; - lastError = err; - emitStatusChange(); - return syncMan.stop(); - } - } + await ctrl.init(); - await ctrl.init(); + await syncNow(name); + bgPrefsSet('sync.enabled', name); + status.state = STATES.connected; + schedule(SYNC_INTERVAL); + emitStatusChange(); +} - await syncMan.syncNow(name); - prefs.set('sync.enabled', name); - status.state = STATES.connected; - schedule(SYNC_INTERVAL); - emitStatusChange(); - }, +export async function stop() { + if (ready.then) await ready; + if (!currentDrive) return; + chrome.alarms.clear('syncNow'); + status.state = STATES.disconnecting; + emitStatusChange(); + try { + await ctrl.uninit(); + await revokeToken(currentDrive.name); + await chromeLocal.remove(STORAGE_KEY + currentDrive.name); + } catch (e) { + } + currentDrive = null; + bgPrefsSet('sync.enabled', 'none'); + status.state = STATES.disconnected; + status.currentDriveName = null; + status.login = false; + emitStatusChange(); +} - async stop() { - if (ready.then) await ready; - if (!currentDrive) return; - chrome.alarms.clear('syncNow'); - status.state = STATES.disconnecting; - emitStatusChange(); - try { - await ctrl.uninit(); - await tokenMan.revokeToken(currentDrive.name); - await chromeLocal.remove(STORAGE_KEY + currentDrive.name); - } catch (e) {} - currentDrive = null; - prefs.set('sync.enabled', 'none'); - status.state = STATES.disconnected; - status.currentDriveName = null; +export async function syncNow() { + if (ready.then) await ready; + if (!currentDrive || !status.login) { + console.warn('cannot sync when disconnected'); + return; + } + try { + await ctrl.syncNow(); + status.errorMessage = null; + lastError = null; + } catch (err) { + err.message = translateErrorMessage(err); + status.errorMessage = err.message; + lastError = err; + if (isGrantError(err)) { status.login = false; - emitStatusChange(); - }, + } + } + emitStatusChange(); +} + +//#endregion +//#region Utils - async syncNow() { - if (ready.then) await ready; - if (!currentDrive || !status.login) { - console.warn('cannot sync when disconnected'); - return; +async function initController() { + ctrl = (await import('db-to-cloud')).dbToCloud({ + onGet: _id => styleMan.uuid2style(_id) || uuidIndex.custom[_id], + async onPut(doc) { + if (!doc) return; // TODO: delete it? + const id = uuidIndex.get(doc._id); + const oldCust = !id && uuidIndex.custom[doc._id]; + const oldDoc = oldCust || styleMan.get(id); + const diff = oldDoc ? compareRevision(oldDoc._rev, doc._rev) : -1; + if (!diff) return; + if (diff > 0) { + putDoc(oldDoc); + } else if (oldCust) { + uuidIndex.custom[doc._id] = doc; + } else { + delete doc.id; + if (id) doc.id = id; + doc.id = await db.styles.put(doc); + await styleMan.handleSave(doc, 'sync'); + } + }, + onDelete(_id, rev) { + const id = uuidIndex.get(_id); + const oldDoc = styleMan.get(id); + return oldDoc && + compareRevision(oldDoc._rev, rev) <= 0 && + styleMan.remove(id, 'sync'); + }, + onFirstSync() { + for (const i of Object.values(uuidIndex.custom).concat(styleMan.getAll())) { + ctrl.put(i._id, i._rev); } - try { - await ctrl.syncNow(); - status.errorMessage = null; - lastError = null; - } catch (err) { - err.message = translateErrorMessage(err); - status.errorMessage = err.message; - lastError = err; - if (isGrantError(err)) { - status.login = false; - } + }, + onProgress(e) { + if (e.phase === 'start') { + status.syncing = true; + } else if (e.phase === 'end') { + status.syncing = false; + status.progress = null; + } else { + status.progress = e; } emitStatusChange(); }, - }; - - //#endregion - //#region Utils - - async function initController() { - await require(['/vendor/db-to-cloud/db-to-cloud']); /* global dbToCloud */ - ctrl = dbToCloud.dbToCloud({ - onGet: _id => styleUtil.uuid2style(_id) || uuidIndex.custom[_id], - async onPut(doc) { - if (!doc) return; // TODO: delete it? - const id = uuidIndex.get(doc._id); - const oldCust = !id && uuidIndex.custom[doc._id]; - const oldDoc = oldCust || styleUtil.id2style(id); - const diff = oldDoc ? compareRevision(oldDoc._rev, doc._rev) : -1; - if (!diff) return; - if (diff > 0) { - syncMan.putDoc(oldDoc); - } else if (oldCust) { - uuidIndex.custom[doc._id] = doc; - } else { - delete doc.id; - if (id) doc.id = id; - doc.id = await db.styles.put(doc); - await styleUtil.handleSave(doc, 'sync'); - } - }, - onDelete(_id, rev) { - const id = uuidIndex.get(_id); - const oldDoc = styleUtil.id2style(id); - return oldDoc && - compareRevision(oldDoc._rev, rev) <= 0 && - styleMan.delete(id, 'sync'); - }, - onFirstSync() { - for (const i of Object.values(uuidIndex.custom).concat(styleMan.getAll())) { - ctrl.put(i._id, i._rev); - } - }, - onProgress(e) { - if (e.phase === 'start') { - status.syncing = true; - } else if (e.phase === 'end') { - status.syncing = false; - status.progress = null; - } else { - status.progress = e; - } - emitStatusChange(); - }, - compareRevision, - getState(drive) { - return chromeLocal.getValue(STORAGE_KEY + drive.name); - }, - setState(drive, state) { - return chromeLocal.setValue(STORAGE_KEY + drive.name, state); - }, - retryMaxAttempts: 10, - retryExp: 1.2, - retryDelay: 6, - }); - } + compareRevision, + getState(drive) { + return chromeLocal.getValue(STORAGE_KEY + drive.name); + }, + setState(drive, state) { + return chromeLocal.setValue(STORAGE_KEY + drive.name, state); + }, + retryMaxAttempts: 10, + retryExp: 1.2, + retryDelay: 6, + }); +} - function emitStatusChange() { - msg.broadcastExtension({method: 'syncStatusUpdate', status}); - iconMan.overrideBadge(getErrorBadge()); - } +function emitStatusChange() { + broadcastExtension({method: 'syncStatusUpdate', status}); + overrideBadge(getErrorBadge()); +} - function isNetworkError(err) { - return ( - err.name === 'TypeError' && /networkerror|failed to fetch/i.test(err.message) || - err.code === 502 - ); - } +function isNetworkError(err) { + return ( + err.name === 'TypeError' && /networkerror|failed to fetch/i.test(err.message) || + err.code === 502 + ); +} - function isGrantError(err) { - if (err.code === 401) return true; - if (err.code === 400 && /invalid_grant/.test(err.message)) return true; - if (err.name === 'TokenError') return true; - return false; - } +function isGrantError(err) { + if (err.code === 401) return true; + if (err.code === 400 && /invalid_grant/.test(err.message)) return true; + if (err.name === 'TokenError') return true; + return false; +} - function getErrorBadge() { - if (status.state === STATES.connected && - (!status.login || lastError && !isNetworkError(lastError))) { - return { - text: 'x', - color: '#F00', - title: !status.login ? 'syncErrorRelogin' : `${ - chrome.i18n.getMessage('syncError') - }\n---------------------\n${ - // splitting to limit each line length - lastError.message.replace(/.{60,}?\s(?=.{30,})/g, '$&\n') - }`, - }; - } +function getErrorBadge() { + if (status.state === STATES.connected && + (!status.login || lastError && !isNetworkError(lastError))) { + return { + text: 'x', + color: '#F00', + title: !status.login ? 'syncErrorRelogin' : `${ + chrome.i18n.getMessage('syncError') + }\n---------------------\n${ + // splitting to limit each line length + lastError.message.replace(/.{60,}?\s(?=.{30,})/g, '$&\n') + }`, + }; } +} - async function getDrive(name) { - if (name === 'dropbox' || name === 'google' || name === 'onedrive' || name === 'webdav') { - const options = await syncMan.getDriveOptions(name); - options.getAccessToken = () => tokenMan.getToken(name); - options.fetch = name === 'webdav' ? fetchWebDAV.bind(options) : fetch; - return dbToCloud.drive[name](options); - } - throw new Error(`unknown cloud name: ${name}`); +async function getDrive(name) { + if (name === 'dropbox' || name === 'google' || name === 'onedrive' || name === 'webdav') { + const options = await getDriveOptions(name); + options.getAccessToken = () => getToken(name); + options.fetch = name === 'webdav' ? fetchWebDAV.bind(options) : fetch; + return (await import('db-to-cloud')).drive[name](options); } + throw new Error(`unknown cloud name: ${name}`); +} - /** @this {Object} DriveOptions */ - function fetchWebDAV(url, init = {}) { - init.credentials = 'omit'; // circumventing nextcloud CSRF token error - init.headers = Object.assign({}, init.headers, { - Authorization: `Basic ${btoa(`${this.username || ''}:${this.password || ''}`)}`, - }); - return fetch(url, init); - } +/** @this {Object} DriveOptions */ +function fetchWebDAV(url, init = {}) { + init.credentials = 'omit'; // circumventing nextcloud CSRF token error + init.headers = Object.assign({}, init.headers, { + Authorization: `Basic ${btoa(`${this.username || ''}:${this.password || ''}`)}`, + }); + return fetch(url, init); +} - function schedule(delay = SYNC_DELAY) { - chrome.alarms.create('syncNow', { - delayInMinutes: delay, // fractional values are supported - periodInMinutes: SYNC_INTERVAL, - }); - } +function schedule(delay = SYNC_DELAY) { + chrome.alarms.create('syncNow', { + delayInMinutes: delay, // fractional values are supported + periodInMinutes: SYNC_INTERVAL, + }); +} - function translateErrorMessage(err) { - if (err.name === 'LockError') { - return browser.i18n.getMessage('syncErrorLock', new Date(err.expire).toLocaleString([], {timeStyle: 'short'})); - } - return err.message || String(err); +function translateErrorMessage(err) { + if (err.name === 'LockError') { + return browser.i18n.getMessage('syncErrorLock', + new Date(err.expire).toLocaleString([], {timeStyle: 'short'})); } + return err.message || String(err); +} - //#endregion -})(); +//#endregion diff --git a/src/background/tab-manager.js b/src/background/tab-manager.js index 17b0d2d2300..d45bb5aee45 100644 --- a/src/background/tab-manager.js +++ b/src/background/tab-manager.js @@ -1,67 +1,65 @@ -/* global bgReady */// common.js -/* global URLS */// toolbox.js -/* global navMan */ -'use strict'; +import {URLS} from '/js/toolbox'; +import {bgReady} from './common'; +import {onUrlChange} from './navigation-manager'; -/* exported tabMan */ -const tabMan = (() => { - const listeners = new Set(); - /** @typedef {{ url:string, styleIds: {[frameId:string]: number[]} }} StyleIdsFrameMap */ - /** @type {Map} */ - const cache = new Map(); - const cacheGet = cache.get.bind(cache); - const cacheSet = cache.set.bind(cache); - chrome.tabs.onRemoved.addListener(tabId => cache.delete(tabId)); - chrome.tabs.onReplaced.addListener((added, removed) => cache.delete(removed)); +const listeners = new Set(); +/** @typedef {{ url:string, styleIds: {[frameId:string]: number[]} }} StyleIdsFrameMap */ +/** @type {Map} */ +const cache = new Map(); +const cacheGet = cache.get.bind(cache); +const cacheSet = cache.set.bind(cache); - bgReady.all.then(() => { - navMan.onUrlChange(({tabId, frameId, url}) => { - if (frameId) return; - let obj, oldUrl; - if ((obj = cacheGet(tabId))) oldUrl = obj.url; - else cacheSet(tabId, obj = {}); - obj.url = url; - if (!URLS.supported(url)) return; - for (const fn of listeners) { - try { - fn({tabId, url, oldUrl}); - } catch (err) { - console.error(err); - } - } - }); - }); +const tabMan = Object.assign(cache, { + onOff(fn, state = true) { + listeners[state ? 'add' : 'delete'](fn); + }, + get(tabId, ...keys) { + let res = cacheGet(tabId); + for (let i = 0; res && i < keys.length; i++) res = res[keys[i]]; + return res; + }, + /** @return {StyleIdsFrameMap|false} */ + getStyleIds: id => (id = cacheGet(id)) && id.styleIds || false, + /** + * number of keys is arbitrary, last arg is value, `undefined` will delete the last key from meta + * (tabId, 'foo', 123) will set tabId's meta to {foo: 123}, + * (tabId, 'foo', 'bar', 'etc', 123) will set tabId's meta to {foo: {bar: {etc: 123}}} + */ + set(tabId, ...args) { + const value = args.pop(); + const lastKey = args.pop(); + const del = value === undefined; + let meta = cacheGet(tabId); + if (!meta) { + if (del) return; + cacheSet(tabId, meta = {}); + } + for (let i = 0, key; meta && i < args.length; i++) { + meta = meta[key = args[i]] || !del && (meta[key] = {}); + } + if (!del) meta[lastKey] = value; + else if (meta) delete meta[lastKey]; + }, +}); - return Object.assign(cache, { - onOff(fn, state = true) { - listeners[state ? 'add' : 'delete'](fn); - }, - get(tabId, ...keys) { - let res = cacheGet(tabId); - for (let i = 0; res && i < keys.length; i++) res = res[keys[i]]; - return res; - }, - /** @return {StyleIdsFrameMap|false} */ - getStyleIds: id => (id = cacheGet(id)) && id.styleIds || false, - /** - * number of keys is arbitrary, last arg is value, `undefined` will delete the last key from meta - * (tabId, 'foo', 123) will set tabId's meta to {foo: 123}, - * (tabId, 'foo', 'bar', 'etc', 123) will set tabId's meta to {foo: {bar: {etc: 123}}} - */ - set(tabId, ...args) { - const value = args.pop(); - const lastKey = args.pop(); - const del = value === undefined; - let meta = cacheGet(tabId); - if (!meta) { - if (del) return; - cacheSet(tabId, meta = {}); +chrome.tabs.onRemoved.addListener(tabId => cache.delete(tabId)); +chrome.tabs.onReplaced.addListener((added, removed) => cache.delete(removed)); +bgReady.all.then(() => { + onUrlChange(({tabId, frameId, url}) => { + if (frameId) return; + let obj, oldUrl; + if ((obj = cacheGet(tabId))) oldUrl = obj.url; + else cacheSet(tabId, obj = {}); + obj.url = url; + if (!URLS.supported(url)) return; + for (const fn of listeners) { + try { + fn({tabId, url, oldUrl}); + } catch (err) { + console.error(err); } - for (let i = 0, key; meta && i < args.length; i++) { - meta = meta[key = args[i]] || !del && (meta[key] = {}); - } - if (!del) meta[lastKey] = value; - else if (meta) delete meta[lastKey]; - }, + } }); -})(); +}); + +export default tabMan; diff --git a/src/background/tab-util.js b/src/background/tab-util.js index ef16a26ff02..0d424369744 100644 --- a/src/background/tab-util.js +++ b/src/background/tab-util.js @@ -1,12 +1,12 @@ -/* global msg */// msg.js -/* global API addAPI */// common.js -/* global FIREFOX getActiveTab */ // toolbox.js -/* global prefs */ -'use strict'; +import browser from '/js/browser'; +import * as msg from '/js/msg'; +import {getActiveTab} from '/js/toolbox'; +import {addAPI, API} from './common'; +import * as prefs from '/js/prefs'; // FF57+ supports openerTabId, but not in Android // (detecting FF57 by the feature it added, not navigator.ua which may be spoofed in about:config) -const HAS_OPENER = (!FIREFOX || window.AbortController) && chrome.windows != null; +const HAS_OPENER = (CHROME || window.AbortController) && chrome.windows != null; const EMPTY_TAB = [ // Chrome and simple forks 'chrome://newtab/', @@ -97,7 +97,7 @@ addAPI(/** @namespace API */ { * @param {boolean} [_.newTab] `true` to force a new tab instead of switching to an existing tab * @returns {Promise} Promise -> opened/activated tab */ -async function openURL({ +export async function openURL({ url, index, openerTabId, @@ -148,12 +148,11 @@ async function activateTab(tab, {url, index, openerTabId} = {}) { return tab; } -/* exported getUrlOrigin */ -function getUrlOrigin(url = '') { +export function getUrlOrigin(url = '') { return url.substring(0, url.indexOf('/', url.indexOf(':') + 3)); } -function waitForTabUrl(tabId) { +export function waitForTabUrl(tabId) { return new Promise(resolve => { browser.tabs.onUpdated.addListener(...[ function onUpdated(updatedId, info, updatedTab) { diff --git a/src/background/token-manager.js b/src/background/token-manager.js index 011a7337b45..64bbd766128 100644 --- a/src/background/token-manager.js +++ b/src/background/token-manager.js @@ -1,270 +1,258 @@ -/* global detectVivaldi isVivaldi */// common.js -/* global FIREFOX clamp URLS */// toolbox.js -/* global waitForTabUrl */// tab-util.js -/* global chromeLocal */// storage-util.js -'use strict'; +import browser from '/js/browser'; +import {clamp, URLS} from '/js/toolbox'; +import {chromeLocal} from '/js/storage-util'; +import {detectVivaldi, isVivaldi} from './common'; +import {waitForTabUrl} from './tab-util'; -/* exported tokenMan */ -const tokenMan = (() => { - const AUTH = { - dropbox: { - flow: 'token', - clientId: 'zg52vphuapvpng9', - authURL: 'https://www.dropbox.com/oauth2/authorize', - tokenURL: 'https://api.dropboxapi.com/oauth2/token', - revoke: token => - fetch('https://api.dropboxapi.com/2/auth/token/revoke', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - }, - }), - }, - google: { - flow: 'code', - clientId: '283762574871-d4u58s4arra5jdan2gr00heasjlttt1e.apps.googleusercontent.com', - clientSecret: 'J0nc5TlR_0V_ex9-sZk-5faf', - authURL: 'https://accounts.google.com/o/oauth2/v2/auth', - authQuery: { - // NOTE: Google needs 'prompt' parameter to deliver multiple refresh - // tokens for multiple machines. - // https://stackoverflow.com/q/18519185 - access_type: 'offline', - prompt: 'consent', - }, - tokenURL: 'https://oauth2.googleapis.com/token', - scopes: ['https://www.googleapis.com/auth/drive.appdata'], - // FIXME: https://github.com/openstyles/stylus/issues/1248 - // revoke: token => { - // const params = {token}; - // return postQuery(`https://accounts.google.com/o/oauth2/revoke?${new URLSearchParams(params)}`); - // }, - }, - onedrive: { - flow: 'code', - clientId: '3864ce03-867c-4ad8-9856-371a097d47b1', - clientSecret: '9Pj=TpsrStq8K@1BiwB9PIWLppM:@s=w', - authURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize', - tokenURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/token', - scopes: ['Files.ReadWrite.AppFolder', 'offline_access'], - }, - userstylesworld: { - flow: 'code', - clientId: 'zeDmKhJIfJqULtcrGMsWaxRtWHEimKgS', - clientSecret: 'wqHsvTuThQmXmDiVvOpZxPwSIbyycNFImpAOTxjaIRqDbsXcTOqrymMJKsOMuibFaij' + - 'ZZAkVYTDbLkQuYFKqgpMsMlFlgwQOYHvHFbgxQHDTwwdOroYhOwFuekCwXUlk', - authURL: URLS.usw + 'api/oauth/style/link', - tokenURL: URLS.usw + 'api/oauth/token', - redirect_uri: 'https://gusted.xyz/callback_helper/', +const AUTH = { + dropbox: { + flow: 'token', + clientId: 'zg52vphuapvpng9', + authURL: 'https://www.dropbox.com/oauth2/authorize', + tokenURL: 'https://api.dropboxapi.com/oauth2/token', + revoke: token => + fetch('https://api.dropboxapi.com/2/auth/token/revoke', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + }, + }), + }, + google: { + flow: 'code', + clientId: '283762574871-d4u58s4arra5jdan2gr00heasjlttt1e.apps.googleusercontent.com', + clientSecret: 'J0nc5TlR_0V_ex9-sZk-5faf', + authURL: 'https://accounts.google.com/o/oauth2/v2/auth', + authQuery: { + // NOTE: Google needs 'prompt' parameter to deliver multiple refresh + // tokens for multiple machines. + // https://stackoverflow.com/q/18519185 + access_type: 'offline', + prompt: 'consent', }, - }; - const NETWORK_LATENCY = 30; // seconds - const DEFAULT_REDIRECT_URI = 'https://clngdbkpkpeebahjckkjfobafhncgmne.chromiumapp.org/'; + tokenURL: 'https://oauth2.googleapis.com/token', + scopes: ['https://www.googleapis.com/auth/drive.appdata'], + // FIXME: https://github.com/openstyles/stylus/issues/1248 + // revoke: token => { + // const params = {token}; + // return postQuery(`https://accounts.google.com/o/oauth2/revoke?${new URLSearchParams(params)}`); + // }, + }, + onedrive: { + flow: 'code', + clientId: '3864ce03-867c-4ad8-9856-371a097d47b1', + clientSecret: '9Pj=TpsrStq8K@1BiwB9PIWLppM:@s=w', + authURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize', + tokenURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/token', + scopes: ['Files.ReadWrite.AppFolder', 'offline_access'], + }, + userstylesworld: { + flow: 'code', + clientId: 'zeDmKhJIfJqULtcrGMsWaxRtWHEimKgS', + clientSecret: 'wqHsvTuThQmXmDiVvOpZxPwSIbyycNFImpAOTxjaIRqDbsXcTOqrymMJKsOMuibFaij' + + 'ZZAkVYTDbLkQuYFKqgpMsMlFlgwQOYHvHFbgxQHDTwwdOroYhOwFuekCwXUlk', + authURL: URLS.usw + 'api/oauth/style/link', + tokenURL: URLS.usw + 'api/oauth/token', + redirect_uri: 'https://gusted.xyz/callback_helper/', + }, +}; +const NETWORK_LATENCY = 30; // seconds +const DEFAULT_REDIRECT_URI = 'https://clngdbkpkpeebahjckkjfobafhncgmne.chromiumapp.org/'; - let alwaysUseTab = !chrome.windows || (FIREFOX ? false : null); +let alwaysUseTab = !chrome.windows || (FIREFOX ? false : null); - class TokenError extends Error { - constructor(provider, message) { - super(`[${provider}] ${message}`); - this.name = 'TokenError'; - this.provider = provider; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, TokenError); - } +class TokenError extends Error { + constructor(provider, message) { + super(`[${provider}] ${message}`); + this.name = 'TokenError'; + this.provider = provider; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, TokenError); } } +} - return { - - buildKeys(name, hooks) { - const prefix = `secure/token/${hooks ? hooks.keyName(name) : name}/`; - const k = { - TOKEN: `${prefix}token`, - EXPIRE: `${prefix}expire`, - REFRESH: `${prefix}refresh`, - }; - k.LIST = Object.values(k); - return k; - }, +function buildKeys(name, hooks) { + const prefix = `secure/token/${hooks ? hooks.keyName(name) : name}/`; + const k = { + TOKEN: `${prefix}token`, + EXPIRE: `${prefix}expire`, + REFRESH: `${prefix}refresh`, + }; + k.LIST = Object.values(k); + return k; +} - getClientId(name) { - return AUTH[name].clientId; - }, +export async function getToken(name, interactive, hooks) { + const k = buildKeys(name, hooks); + const obj = await chromeLocal.get(k.LIST); + if (obj[k.TOKEN]) { + if (!obj[k.EXPIRE] || Date.now() < obj[k.EXPIRE]) { + return obj[k.TOKEN]; + } + if (obj[k.REFRESH]) { + return refreshToken(name, k, obj); + } + } + if (!interactive) { + throw new TokenError(name, 'Token is missing'); + } + return authUser(k, name, interactive, hooks); +} - async getToken(name, interactive, hooks) { - const k = tokenMan.buildKeys(name, hooks); - const obj = await chromeLocal.get(k.LIST); - if (obj[k.TOKEN]) { - if (!obj[k.EXPIRE] || Date.now() < obj[k.EXPIRE]) { - return obj[k.TOKEN]; - } - if (obj[k.REFRESH]) { - return refreshToken(name, k, obj); - } - } - if (!interactive) { - throw new TokenError(name, 'Token is missing'); - } - return authUser(k, name, interactive, hooks); - }, +export async function revokeToken(name, hooks) { + const provider = AUTH[name]; + const k = buildKeys(name, hooks); + if (provider.revoke) { + try { + const token = await chromeLocal.getValue(k.TOKEN); + if (token) await provider.revoke(token); + } catch (e) { + console.error(e); + } + } + await chromeLocal.remove(k.LIST); +} - async revokeToken(name, hooks) { - const provider = AUTH[name]; - const k = tokenMan.buildKeys(name, hooks); - if (provider.revoke) { - try { - const token = await chromeLocal.getValue(k.TOKEN); - if (token) await provider.revoke(token); - } catch (e) { - console.error(e); - } - } - await chromeLocal.remove(k.LIST); - }, +async function refreshToken(name, k, obj) { + if (!obj[k.REFRESH]) { + throw new TokenError(name, 'No refresh token'); + } + const provider = AUTH[name]; + const body = { + client_id: provider.clientId, + refresh_token: obj[k.REFRESH], + grant_type: 'refresh_token', + scope: provider.scopes.join(' '), }; + if (provider.clientSecret) { + body.client_secret = provider.clientSecret; + } + const result = await postQuery(provider.tokenURL, body); + if (!result.refresh_token) { + // reuse old refresh token + result.refresh_token = obj[k.REFRESH]; + } + return handleTokenResult(result, k); +} - async function refreshToken(name, k, obj) { - if (!obj[k.REFRESH]) { - throw new TokenError(name, 'No refresh token'); +async function authUser(keys, name, interactive = false, hooks = null) { + const provider = AUTH[name]; + const state = Math.random().toFixed(8).slice(2); + const query = { + response_type: provider.flow, + client_id: provider.clientId, + redirect_uri: provider.redirect_uri || DEFAULT_REDIRECT_URI, + state, + }; + if (provider.scopes) { + query.scope = provider.scopes.join(' '); + } + if (provider.authQuery) { + Object.assign(query, provider.authQuery); + } + if (alwaysUseTab == null) { + alwaysUseTab = await detectVivaldiWebRequestBug(); + } + if (hooks) hooks.query(query); + const url = `${provider.authURL}?${new URLSearchParams(query)}`; + const width = clamp(screen.availWidth - 100, 400, 800); + const height = clamp(screen.availHeight - 100, 200, 800); + const wnd = !alwaysUseTab && await browser.windows.getLastFocused(); + const finalUrl = await (await import('webext-launch-web-auth-flow')).launchWebAuthFlow({ + url, + alwaysUseTab, + interactive, + redirect_uri: query.redirect_uri, + windowOptions: wnd && Object.assign({ + state: 'normal', + width, + height, + }, wnd.state !== 'minimized' && { + // Center the popup to the current window + top: Math.ceil(wnd.top + (wnd.height - width) / 2), + left: Math.ceil(wnd.left + (wnd.width - width) / 2), + }), + }); + const params = new URLSearchParams( + provider.flow === 'token' ? + new URL(finalUrl).hash.slice(1) : + new URL(finalUrl).search.slice(1) + ); + if (params.get('state') !== state) { + throw new TokenError(name, `Unexpected state: ${params.get('state')}, expected: ${state}`); + } + let result; + if (provider.flow === 'token') { + const obj = {}; + for (const [key, value] of params) { + obj[key] = value; } - const provider = AUTH[name]; + result = obj; + } else { + const code = params.get('code'); const body = { + code, + grant_type: 'authorization_code', client_id: provider.clientId, - refresh_token: obj[k.REFRESH], - grant_type: 'refresh_token', - scope: provider.scopes.join(' '), + redirect_uri: query.redirect_uri, + state, }; if (provider.clientSecret) { body.client_secret = provider.clientSecret; } - const result = await postQuery(provider.tokenURL, body); - if (!result.refresh_token) { - // reuse old refresh token - result.refresh_token = obj[k.REFRESH]; - } - return handleTokenResult(result, k); - } - - async function authUser(keys, name, interactive = false, hooks = null) { - await require(['/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow']); - /* global webextLaunchWebAuthFlow */ - const provider = AUTH[name]; - const state = Math.random().toFixed(8).slice(2); - const query = { - response_type: provider.flow, - client_id: provider.clientId, - redirect_uri: provider.redirect_uri || DEFAULT_REDIRECT_URI, - state, - }; - if (provider.scopes) { - query.scope = provider.scopes.join(' '); - } - if (provider.authQuery) { - Object.assign(query, provider.authQuery); - } - if (alwaysUseTab == null) { - alwaysUseTab = await detectVivaldiWebRequestBug(); - } - if (hooks) hooks.query(query); - const url = `${provider.authURL}?${new URLSearchParams(query)}`; - const width = clamp(screen.availWidth - 100, 400, 800); - const height = clamp(screen.availHeight - 100, 200, 800); - const wnd = !alwaysUseTab && await browser.windows.getLastFocused(); - const finalUrl = await webextLaunchWebAuthFlow({ - url, - alwaysUseTab, - interactive, - redirect_uri: query.redirect_uri, - windowOptions: wnd && Object.assign({ - state: 'normal', - width, - height, - }, wnd.state !== 'minimized' && { - // Center the popup to the current window - top: Math.ceil(wnd.top + (wnd.height - width) / 2), - left: Math.ceil(wnd.left + (wnd.width - width) / 2), - }), - }); - const params = new URLSearchParams( - provider.flow === 'token' ? - new URL(finalUrl).hash.slice(1) : - new URL(finalUrl).search.slice(1) - ); - if (params.get('state') !== state) { - throw new TokenError(name, `Unexpected state: ${params.get('state')}, expected: ${state}`); - } - let result; - if (provider.flow === 'token') { - const obj = {}; - for (const [key, value] of params) { - obj[key] = value; - } - result = obj; - } else { - const code = params.get('code'); - const body = { - code, - grant_type: 'authorization_code', - client_id: provider.clientId, - redirect_uri: query.redirect_uri, - state, - }; - if (provider.clientSecret) { - body.client_secret = provider.clientSecret; - } - result = await postQuery(provider.tokenURL, body); - } - return handleTokenResult(result, keys); + result = await postQuery(provider.tokenURL, body); } + return handleTokenResult(result, keys); +} - async function handleTokenResult(result, k) { - await chromeLocal.set({ - [k.TOKEN]: result.access_token, - [k.EXPIRE]: result.expires_in - ? Date.now() + (result.expires_in - NETWORK_LATENCY) * 1000 - : undefined, - [k.REFRESH]: result.refresh_token, - }); - return result.access_token; - } +async function handleTokenResult(result, k) { + await chromeLocal.set({ + [k.TOKEN]: result.access_token, + [k.EXPIRE]: result.expires_in + ? Date.now() + (result.expires_in - NETWORK_LATENCY) * 1000 + : undefined, + [k.REFRESH]: result.refresh_token, + }); + return result.access_token; +} - async function postQuery(url, body) { - const options = { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: body ? new URLSearchParams(body) : null, - }; - const r = await fetch(url, options); - if (r.ok) { - return r.json(); - } - const text = await r.text(); - const err = new Error(`Failed to fetch (${r.status}): ${text}`); - err.code = r.status; - throw err; +async function postQuery(url, body) { + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: body ? new URLSearchParams(body) : null, + }; + const r = await fetch(url, options); + if (r.ok) { + return r.json(); } + const text = await r.text(); + const err = new Error(`Failed to fetch (${r.status}): ${text}`); + err.code = r.status; + throw err; +} - async function detectVivaldiWebRequestBug() { - // Workaround for https://github.com/openstyles/stylus/issues/1182 - if (isVivaldi == null ? await detectVivaldi() === false : !isVivaldi) { - return false; - } - let bugged = true; - const TEST_URL = chrome.runtime.getURL('manifest.json'); - const check = ({url}) => { - bugged = url !== TEST_URL; - }; - chrome.webRequest.onBeforeRequest.addListener(check, {urls: [TEST_URL], types: ['main_frame']}); - const {tabs: [tab]} = await browser.windows.create({ - type: 'popup', - state: 'minimized', - url: TEST_URL, - }); - await waitForTabUrl(tab.id); - chrome.windows.remove(tab.windowId); - chrome.webRequest.onBeforeRequest.removeListener(check); - return bugged; +async function detectVivaldiWebRequestBug() { + // Workaround for https://github.com/openstyles/stylus/issues/1182 + if (isVivaldi == null ? await detectVivaldi() === false : !isVivaldi) { + return false; } -})(); + let bugged = true; + const TEST_URL = chrome.runtime.getURL('manifest.json'); + const check = ({url}) => { + bugged = url !== TEST_URL; + }; + chrome.webRequest.onBeforeRequest.addListener(check, {urls: [TEST_URL], types: ['main_frame']}); + const {tabs: [tab]} = await browser.windows.create({ + type: 'popup', + state: 'minimized', + url: TEST_URL, + }); + await waitForTabUrl(tab.id); + chrome.windows.remove(tab.windowId); + chrome.webRequest.onBeforeRequest.removeListener(check); + return bugged; +} diff --git a/src/background/update-manager.js b/src/background/update-manager.js index 2c8ea30c033..9da456b00d5 100644 --- a/src/background/update-manager.js +++ b/src/background/update-manager.js @@ -1,310 +1,301 @@ -/* global API */// msg.js -/* global bgReady download */// common.js -/* global UCD URLS debounce deepMerge ignoreChromeError */// toolbox.js -/* global calcStyleDigest styleSectionsEqual */ // sections-util.js -/* global chromeLocal */// storage-util.js -/* global compareVersion */// cmpver.js -/* global db */ -/* global prefs */ -/* global styleMan */ -'use strict'; +import compareVersion from '/js/cmpver'; +import * as prefs from '/js/prefs'; +import {calcStyleDigest, styleSectionsEqual} from '/js/sections-util'; +import {chromeLocal} from '/js/storage-util'; +import {debounce, deepMerge, ignoreChromeError, UCD, URLS} from '/js/toolbox'; +import {API, bgReady} from './common'; +import db from './db'; +import download from './download'; +import {getAll} from './style-manager'; -/* exported updateMan */ -const updateMan = (() => { - const STATES = /** @namespace UpdaterStates */ { - UPDATED: 'updated', - SKIPPED: 'skipped', - UNREACHABLE: 'server unreachable', - // details for SKIPPED status - EDITED: 'locally edited', - MAYBE_EDITED: 'may be locally edited', - SAME_MD5: 'up-to-date: MD5 is unchanged', - SAME_CODE: 'up-to-date: code sections are unchanged', - SAME_VERSION: 'up-to-date: version is unchanged', - ERROR_MD5: 'error: MD5 is invalid', - ERROR_JSON: 'error: JSON is invalid', - ERROR_VERSION: 'error: version is older than installed style', - }; - const RH_ETAG = {responseHeaders: ['etag']}; // a hashsum of file contents - const RX_DATE2VER = new RegExp([ - /^(\d{4})/, - /(0[1-9]|1(?:0|[12](?=\d\d))?|[2-9])/, // in ambiguous cases like yyyy123 the month will be 1 - /(0[1-9]|[1-2][0-9]?|3[0-1]?|[4-9])/, - /\.([01][0-9]?|2[0-3]?|[3-9])/, - /\.([0-5][0-9]?|[6-9])$/, - ].map(rx => rx.source).join('')); - const ALARM_NAME = 'scheduledUpdate'; - const MIN_INTERVAL_MS = 60e3; - const RETRY_ERRORS = [ - 503, // service unavailable - 429, // too many requests - ]; - let lastUpdateTime; - let checkingAll = false; - let logQueue = []; - let logLastWriteTime = 0; +const STATES = /** @namespace UpdaterStates */ { + UPDATED: 'updated', + SKIPPED: 'skipped', + UNREACHABLE: 'server unreachable', + // details for SKIPPED status + EDITED: 'locally edited', + MAYBE_EDITED: 'may be locally edited', + SAME_MD5: 'up-to-date: MD5 is unchanged', + SAME_CODE: 'up-to-date: code sections are unchanged', + SAME_VERSION: 'up-to-date: version is unchanged', + ERROR_MD5: 'error: MD5 is invalid', + ERROR_JSON: 'error: JSON is invalid', + ERROR_VERSION: 'error: version is older than installed style', +}; +export const getStates = () => STATES; +const RH_ETAG = {responseHeaders: ['etag']}; // a hashsum of file contents +const RX_DATE2VER = new RegExp([ + /^(\d{4})/, + /(0[1-9]|1(?:0|[12](?=\d\d))?|[2-9])/, // in ambiguous cases like yyyy123 the month will be 1 + /(0[1-9]|[1-2][0-9]?|3[0-1]?|[4-9])/, + /\.([01][0-9]?|2[0-3]?|[3-9])/, + /\.([0-5][0-9]?|[6-9])$/, +].map(rx => rx.source).join('')); +const ALARM_NAME = 'scheduledUpdate'; +const MIN_INTERVAL_MS = 60e3; +const RETRY_ERRORS = [ + 503, // service unavailable + 429, // too many requests +]; +let lastUpdateTime; +let checkingAll = false; +let logQueue = []; +let logLastWriteTime = 0; - bgReady.all.then(async () => { - lastUpdateTime = await chromeLocal.getValue('lastUpdateTime') || Date.now(); - prefs.subscribe('updateInterval', schedule, true); - chrome.alarms.onAlarm.addListener(onAlarm); - }); +bgReady.all.then(async () => { + lastUpdateTime = await chromeLocal.getValue('lastUpdateTime') || Date.now(); + prefs.subscribe('updateInterval', schedule, true); + chrome.alarms.onAlarm.addListener(onAlarm); +}); - return { - checkAllStyles, - checkStyle, - getStates: () => STATES, - }; +export async function checkAllStyles({ + save = true, + ignoreDigest, + observe, + onlyEnabled = prefs.get('updateOnlyEnabled'), +} = {}) { + resetInterval(); + checkingAll = true; + const port = observe && chrome.runtime.connect({name: 'updater'}); + const styles = getAll().filter(s => + s.updateUrl && + s.updatable !== false && + (!onlyEnabled || s.enabled)); + if (port) port.postMessage({count: styles.length}); + log(''); + log(`${save ? 'Scheduled' : 'Manual'} update check for ${styles.length} styles`); + await Promise.all( + styles.map(style => + checkStyle({style, port, save, ignoreDigest}))); + if (port) port.postMessage({done: true}); + if (port) port.disconnect(); + log(''); + checkingAll = false; +} - async function checkAllStyles({ - save = true, - ignoreDigest, - observe, - onlyEnabled = prefs.get('updateOnlyEnabled'), - } = {}) { - resetInterval(); - checkingAll = true; - const port = observe && chrome.runtime.connect({name: 'updater'}); - const styles = styleMan.getAll().filter(s => - s.updateUrl && - s.updatable !== false && - (!onlyEnabled || s.enabled)); - if (port) port.postMessage({count: styles.length}); - log(''); - log(`${save ? 'Scheduled' : 'Manual'} update check for ${styles.length} styles`); - await Promise.all( - styles.map(style => - checkStyle({style, port, save, ignoreDigest}))); - if (port) port.postMessage({done: true}); - if (port) port.disconnect(); - log(''); - checkingAll = false; - } +/** + * @param {{ + id?: number, + style?: StyleObj, + port?: chrome.runtime.Port, + save?: boolean, + ignoreDigest?: boolean, + }} opts + * @returns {{ + style: StyleObj, + updated?: boolean, + error?: any, + STATES: UpdaterStates, + }} - /** - * @param {{ - id?: number, - style?: StyleObj, - port?: chrome.runtime.Port, - save?: boolean, - ignoreDigest?: boolean, - }} opts - * @returns {{ - style: StyleObj, - updated?: boolean, - error?: any, - STATES: UpdaterStates, - }} + Original style digests are calculated in these cases: + * style is installed or updated from server + * non-usercss style is checked for an update and styleSectionsEqual considers it unchanged - Original style digests are calculated in these cases: - * style is installed or updated from server - * non-usercss style is checked for an update and styleSectionsEqual considers it unchanged + Update check proceeds in these cases: + * style has the original digest and it's equal to the current digest + * [ignoreDigest: true] style doesn't yet have the original digest but we ignore it + * [ignoreDigest: none/false] style doesn't yet have the original digest + so we compare the code to the server code and if it's the same we save the digest, + otherwise we skip the style and report MAYBE_EDITED status - Update check proceeds in these cases: - * style has the original digest and it's equal to the current digest - * [ignoreDigest: true] style doesn't yet have the original digest but we ignore it - * [ignoreDigest: none/false] style doesn't yet have the original digest - so we compare the code to the server code and if it's the same we save the digest, - otherwise we skip the style and report MAYBE_EDITED status + 'ignoreDigest' option is set on the second manual individual update check on the manage page. + */ +export async function checkStyle(opts) { + let {id} = opts; + const { + style = styleMan.get(id), + ignoreDigest, + port, + save, + } = opts; + if (!id) id = style.id; + const {md5Url} = style; + let {[UCD]: ucd, updateUrl} = style; + let res, state; + try { + await checkIfEdited(); + res = { + style: await (ucd && !md5Url ? updateUsercss : updateUSO)().then(maybeSave), + updated: true, + }; + state = STATES.UPDATED; + } catch (err) { + const error = err === 0 && STATES.UNREACHABLE || + err && err.message || + err; + res = {error, style, STATES}; + state = `${STATES.SKIPPED} (${Array.isArray(err) ? err[0].message : error})`; + } + log(`${state} #${id} ${style.customName || style.name}`); + if (port) port.postMessage(res); + return res; - 'ignoreDigest' option is set on the second manual individual update check on the manage page. - */ - async function checkStyle(opts) { - let {id} = opts; - const { - style = styleMan.get(id), - ignoreDigest, - port, - save, - } = opts; - if (!id) id = style.id; - const {md5Url} = style; - let {[UCD]: ucd, updateUrl} = style; - let res, state; - try { - await checkIfEdited(); - res = { - style: await (ucd && !md5Url ? updateUsercss : updateUSO)().then(maybeSave), - updated: true, - }; - state = STATES.UPDATED; - } catch (err) { - const error = err === 0 && STATES.UNREACHABLE || - err && err.message || - err; - res = {error, style, STATES}; - state = `${STATES.SKIPPED} (${Array.isArray(err) ? err[0].message : error})`; + async function checkIfEdited() { + if (!ignoreDigest && + style.originalDigest && + style.originalDigest !== await calcStyleDigest(style)) { + return Promise.reject(STATES.EDITED); } - log(`${state} #${id} ${style.customName || style.name}`); - if (port) port.postMessage(res); - return res; + } - async function checkIfEdited() { - if (!ignoreDigest && - style.originalDigest && - style.originalDigest !== await calcStyleDigest(style)) { - return Promise.reject(STATES.EDITED); - } + async function updateUSO() { + const md5 = await tryDownload(md5Url); + if (!md5 || md5.length !== 32) { + return Promise.reject(STATES.ERROR_MD5); } - - async function updateUSO() { - const md5 = await tryDownload(md5Url); - if (!md5 || md5.length !== 32) { - return Promise.reject(STATES.ERROR_MD5); - } - if (md5 === style.originalMd5 && style.originalDigest && !ignoreDigest) { - return Promise.reject(STATES.SAME_MD5); - } - const usoId = +md5Url.match(/\/(\d+)/)[1]; - let varsUrl = ''; - if (!ucd) { - ucd = {}; - varsUrl = updateUrl; - } - updateUrl = style.updateUrl = `${URLS.usoApi}Css/${usoId}`; - const {result: css} = await tryDownload(updateUrl, {responseType: 'json'}); - const json = await updateUsercss(css) - || await API.uso.toUsercss(usoId, varsUrl, css, style, md5, md5Url); - json.originalMd5 = md5; - return json; + if (md5 === style.originalMd5 && style.originalDigest && !ignoreDigest) { + return Promise.reject(STATES.SAME_MD5); } - - async function updateUsercss(css) { - let oldVer = ucd.version; - let {etag: oldEtag, updateUrl} = style; - const m2 = (css || URLS.extractUsoaId(updateUrl)) && - await API.uso.getEmbeddedMeta(css || style.sourceCode); - if (m2 && m2.updateUrl) { - updateUrl = m2.updateUrl; - oldVer = m2[UCD].version || '0'; - oldEtag = ''; - } else if (css) { - return; - } - if (oldEtag && oldEtag === await downloadEtag()) { - return Promise.reject(STATES.SAME_CODE); - } - // TODO: when sourceCode is > 100kB use http range request(s) for version check - const {headers: {etag}, response} = await tryDownload(updateUrl, RH_ETAG); - const json = await API.usercss.buildMeta({sourceCode: response, etag, updateUrl}); - const delta = compareVersion(json[UCD].version, oldVer); - let err; - if (!delta && !ignoreDigest) { - // re-install is invalid in a soft upgrade - err = response === style.sourceCode - ? STATES.SAME_CODE - : !URLS.isLocalhost(updateUrl) && STATES.SAME_VERSION; - } - if (delta < 0) { - // downgrade is always invalid - err = STATES.ERROR_VERSION; - } - if (err && etag && !style.etag) { - // first check of ETAG, gonna write it directly to DB as it's too trivial to sync or announce - style.etag = etag; - await db.styles.put(style); - } - return err - ? Promise.reject(err) - : json; + const usoId = +md5Url.match(/\/(\d+)/)[1]; + let varsUrl = ''; + if (!ucd) { + ucd = {}; + varsUrl = updateUrl; } + updateUrl = style.updateUrl = `${URLS.usoApi}Css/${usoId}`; + const {result: css} = await tryDownload(updateUrl, {responseType: 'json'}); + const json = await updateUsercss(css) + || await API.uso.toUsercss(usoId, varsUrl, css, style, md5, md5Url); + json.originalMd5 = md5; + return json; + } - async function maybeSave(json) { - json.id = id; - // keep current state - delete json.customName; - delete json.enabled; - const newStyle = Object.assign({}, style, json); - newStyle.updateDate = getDateFromVer(newStyle) || Date.now(); - // update digest even if save === false as there might be just a space added etc. - if (!ucd && styleSectionsEqual(json, style)) { - style.originalDigest = (await styleMan.install(newStyle)).originalDigest; - return Promise.reject(STATES.SAME_CODE); - } - if (!style.originalDigest && !ignoreDigest) { - return Promise.reject(STATES.MAYBE_EDITED); - } - return !save ? newStyle : - ucd ? API.usercss.install(newStyle, {dup: style}) - : styleMan.install(newStyle); + async function updateUsercss(css) { + let oldVer = ucd.version; + let {etag: oldEtag, updateUrl} = style; + const m2 = (css || URLS.extractUsoaId(updateUrl)) && + await API.uso.getEmbeddedMeta(css || style.sourceCode); + if (m2 && m2.updateUrl) { + updateUrl = m2.updateUrl; + oldVer = m2[UCD].version || '0'; + oldEtag = ''; + } else if (css) { + return; } - - async function tryDownload(url, params) { - let {retryDelay = 1000} = opts; - while (true) { - try { - params = deepMerge(params || {}, {headers: {'Cache-Control': 'no-cache'}}); - return await download(url, params); - } catch (code) { - if (!RETRY_ERRORS.includes(code) || - retryDelay > MIN_INTERVAL_MS) { - return Promise.reject(code); - } - } - retryDelay *= 1.25; - await new Promise(resolve => setTimeout(resolve, retryDelay)); - } + if (oldEtag && oldEtag === await downloadEtag()) { + return Promise.reject(STATES.SAME_CODE); } - - async function downloadEtag() { - const opts = Object.assign({method: 'head'}, RH_ETAG); - const req = await tryDownload(style.updateUrl, opts); - return req.headers.etag; + // TODO: when sourceCode is > 100kB use http range request(s) for version check + const {headers: {etag}, response} = await tryDownload(updateUrl, RH_ETAG); + const json = await API.usercss.buildMeta({sourceCode: response, etag, updateUrl}); + const delta = compareVersion(json[UCD].version, oldVer); + let err; + if (!delta && !ignoreDigest) { + // re-install is invalid in a soft upgrade + err = response === style.sourceCode + ? STATES.SAME_CODE + : !URLS.isLocalhost(updateUrl) && STATES.SAME_VERSION; + } + if (delta < 0) { + // downgrade is always invalid + err = STATES.ERROR_VERSION; } + if (err && etag && !style.etag) { + // first check of ETAG, gonna write it directly to DB as it's too trivial to sync or announce + style.etag = etag; + await db.styles.put(style); + } + return err + ? Promise.reject(err) + : json; + } - function getDateFromVer(style) { - const m = RX_DATE2VER.exec((style[UCD] || {}).version); - if (m) { - m[2]--; // month is 0-based in `Date` constructor - return new Date(...m.slice(1)).getTime(); - } + async function maybeSave(json) { + json.id = id; + // keep current state + delete json.customName; + delete json.enabled; + const newStyle = Object.assign({}, style, json); + newStyle.updateDate = getDateFromVer(newStyle) || Date.now(); + // update digest even if save === false as there might be just a space added etc. + if (!ucd && styleSectionsEqual(json, style)) { + style.originalDigest = (await styleMan.install(newStyle)).originalDigest; + return Promise.reject(STATES.SAME_CODE); } + if (!style.originalDigest && !ignoreDigest) { + return Promise.reject(STATES.MAYBE_EDITED); + } + return !save ? newStyle : + ucd ? API.usercss.install(newStyle, {dup: style}) + : styleMan.install(newStyle); } - function schedule() { - const interval = prefs.get('updateInterval') * 60 * 60 * 1000; - if (interval > 0) { - const elapsed = Math.max(0, Date.now() - lastUpdateTime); - chrome.alarms.create(ALARM_NAME, { - when: Date.now() + Math.max(MIN_INTERVAL_MS, interval - elapsed), - }); - } else { - chrome.alarms.clear(ALARM_NAME, ignoreChromeError); + async function tryDownload(url, params) { + let {retryDelay = 1000} = opts; + while (true) { + try { + params = deepMerge(params || {}, {headers: {'Cache-Control': 'no-cache'}}); + return await download(url, params); + } catch (code) { + if (!RETRY_ERRORS.includes(code) || + retryDelay > MIN_INTERVAL_MS) { + return Promise.reject(code); + } + } + retryDelay *= 1.25; + await new Promise(resolve => setTimeout(resolve, retryDelay)); } } - function onAlarm({name}) { - if (name === ALARM_NAME) checkAllStyles(); + async function downloadEtag() { + const opts = Object.assign({method: 'head'}, RH_ETAG); + const req = await tryDownload(style.updateUrl, opts); + return req.headers.etag; } - function resetInterval() { - chromeLocal.setValue('lastUpdateTime', lastUpdateTime = Date.now()); - schedule(); + function getDateFromVer(style) { + const m = RX_DATE2VER.exec((style[UCD] || {}).version); + if (m) { + m[2]--; // month is 0-based in `Date` constructor + return new Date(...m.slice(1)).getTime(); + } } +} - function log(text) { - logQueue.push({text, time: new Date().toLocaleString()}); - debounce(flushQueue, text && checkingAll ? 1000 : 0); +function schedule() { + const interval = prefs.get('updateInterval') * 60 * 60 * 1000; + if (interval > 0) { + const elapsed = Math.max(0, Date.now() - lastUpdateTime); + chrome.alarms.create(ALARM_NAME, { + when: Date.now() + Math.max(MIN_INTERVAL_MS, interval - elapsed), + }); + } else { + chrome.alarms.clear(ALARM_NAME, ignoreChromeError); } +} - async function flushQueue(lines) { - if (!lines) { - flushQueue(await chromeLocal.getValue('updateLog') || []); - return; - } - const time = Date.now() - logLastWriteTime > 11e3 ? - logQueue[0].time + ' ' : - ''; - if (logQueue[0] && !logQueue[0].text) { - logQueue.shift(); - if (lines[lines.length - 1]) lines.push(''); - } - lines.splice(0, lines.length - 1000); - lines.push(time + (logQueue[0] && logQueue[0].text || '')); - lines.push(...logQueue.slice(1).map(item => item.text)); +function onAlarm({name}) { + if (name === ALARM_NAME) checkAllStyles(); +} - chromeLocal.setValue('updateLog', lines); - logLastWriteTime = Date.now(); - logQueue = []; +function resetInterval() { + chromeLocal.setValue('lastUpdateTime', lastUpdateTime = Date.now()); + schedule(); +} + +function log(text) { + logQueue.push({text, time: new Date().toLocaleString()}); + debounce(flushQueue, text && checkingAll ? 1000 : 0); +} + +async function flushQueue(lines) { + if (!lines) { + flushQueue(await chromeLocal.getValue('updateLog') || []); + return; } -})(); + const time = Date.now() - logLastWriteTime > 11e3 ? + logQueue[0].time + ' ' : + ''; + if (logQueue[0] && !logQueue[0].text) { + logQueue.shift(); + if (lines[lines.length - 1]) lines.push(''); + } + lines.splice(0, lines.length - 1000); + lines.push(time + (logQueue[0] && logQueue[0].text || '')); + lines.push(...logQueue.slice(1).map(item => item.text)); + + chromeLocal.setValue('updateLog', lines); + logLastWriteTime = Date.now(); + logQueue = []; +} diff --git a/src/background/usercss-install-helper.js b/src/background/usercss-install-helper.js index 58399de190d..35b72c699e8 100644 --- a/src/background/usercss-install-helper.js +++ b/src/background/usercss-install-helper.js @@ -1,127 +1,128 @@ -/* global RX_META URLS */// toolbox.js -/* global addAPI bgReady download */// common.js -/* global prefs */ -/* global tabMan */// tab-manager.js -/* global openURL */// tab-util.js -'use strict'; +import browser from '/js/browser'; +import * as prefs from '/js/prefs'; +import {RX_META, URLS} from '/js/toolbox'; +import {addAPI, bgReady} from './common'; +import download from './download'; +import tabMan from './tab-manager'; +import {openURL} from './tab-util'; -bgReady.all.then(() => { - const installCodeCache = {}; +const installCodeCache = {}; - addAPI(/** @namespace API */ { - usercss: { - getInstallCode(url) { - // when the installer tab is reloaded after the cache is expired, this will throw intentionally - const {code, timer} = installCodeCache[url]; - clearInstallCode(url); - clearTimeout(timer); - return code; - }, +addAPI(/** @namespace API */ { + usercss: { + getInstallCode(url) { + // when the installer tab is reloaded after the cache is expired, this will throw intentionally + const {code, timer} = installCodeCache[url]; + clearInstallCode(url); + clearTimeout(timer); + return code; }, - }); + }, +}); +bgReady.all.then(() => { prefs.subscribe('urlInstaller', toggle, true); +}); - function toggle(key, val) { - chrome.webRequest.onHeadersReceived.removeListener(maybeInstallByMime); - tabMan.onOff(maybeInstall, val); - const urls = val ? [''] : [ - /* Known distribution sites where we ignore urlInstaller option, because - they open .user.css URL only when the "Install" button is clicked. - We can't be sure of it on general-purpose sites like github.com. */ - URLS.usw, - ...URLS.usoaRaw, - ...['greasy', 'sleazy'].map(h => `https://update.${h}fork.org/`), - ]; - chrome.webRequest.onHeadersReceived.addListener(maybeInstallByMime, { - urls: urls.reduce(reduceUsercssGlobs, []), - types: ['main_frame'], - }, ['responseHeaders', 'blocking']); - } +function toggle(key, val) { + chrome.webRequest.onHeadersReceived.removeListener(maybeInstallByMime); + tabMan.onOff(maybeInstall, val); + const urls = val ? [''] : [ + /* Known distribution sites where we ignore urlInstaller option, because + they open .user.css URL only when the "Install" button is clicked. + We can't be sure of it on general-purpose sites like github.com. */ + URLS.usw, + ...URLS.usoaRaw, + ...['greasy', 'sleazy'].map(h => `https://update.${h}fork.org/`), + ]; + chrome.webRequest.onHeadersReceived.addListener(maybeInstallByMime, { + urls: urls.reduce(reduceUsercssGlobs, []), + types: ['main_frame'], + }, ['responseHeaders', 'blocking']); +} - function clearInstallCode(url) { - return delete installCodeCache[url]; - } +function clearInstallCode(url) { + return delete installCodeCache[url]; +} - /** Ignoring .user.css response that is not a plain text but a web page. - * Not using a whitelist of types as the possibilities are endless e.g. text/x-css-stylus */ - function isContentTypeText(type) { - return /^text\/(?!html)/i.test(type); - } +/** Ignoring .user.css response that is not a plain text but a web page. + * Not using a whitelist of types as the possibilities are endless e.g. text/x-css-stylus */ +function isContentTypeText(type) { + return /^text\/(?!html)/i.test(type); +} - // in Firefox we have to use a content script to read file:// - async function loadFromFile(tabId) { - return (await browser.tabs.executeScript(tabId, {file: '/content/install-hook-usercss.js'}))[0]; - } +// in Firefox we have to use a content script to read file:// +async function loadFromFile(tabId) { + return (await browser.tabs.executeScript(tabId, {file: '/content/install-hook-usercss.js'}))[0]; +} - async function loadFromUrl(tabId, url) { - return ( - url.startsWith('file:') || - tabMan.get(tabId, isContentTypeText.name) - ) && download(url); - } +async function loadFromUrl(tabId, url) { + return ( + url.startsWith('file:') || + tabMan.get(tabId, isContentTypeText.name) + ) && download(url); +} - function makeInstallerUrl(url) { - return `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`; - } +function makeInstallerUrl(url) { + return `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`; +} - function reduceUsercssGlobs(res, host) { - res.push(...'%css,%less,%styl' - .replace(/%\w+/g, host ? '$&*' : '$&,$&?*') - .replace(/%/g, `${host || '*://*/'}*.user.`) - .split(',')); - return res; - } +function reduceUsercssGlobs(res, host) { + res.push(...'%css,%less,%styl' + .replace(/%\w+/g, host ? '$&*' : '$&,$&?*') + .replace(/%/g, `${host || '*://*/'}*.user.`) + .split(',')); + return res; +} - async function maybeInstall({tabId, url, oldUrl = ''}) { - if (url.includes('.user.') && - tabMan.get(tabId, isContentTypeText.name) !== false && - /^(https?|file|ftps?):/.test(url) && - /\.user\.(css|less|styl)$/.test(url.split(/[#?]/, 1)[0]) && - !oldUrl.startsWith(makeInstallerUrl(url))) { - const inTab = url.startsWith('file:') && !chrome.app; - const code = await (inTab ? loadFromFile : loadFromUrl)(tabId, url); - if (!/^\s* h.name.toLowerCase() === 'content-type'); - const isText = h && isContentTypeText(h.value); - tabMan.set(tabId, isContentTypeText.name, isText); - if (isText) { - openInstallerPage(tabId, url, {}); - // Silently suppress navigation. - // Don't redirect to the install URL as it'll flash the text! - return {cancel: true}; - } +function maybeInstallByMime({tabId, url, responseHeaders}) { + const h = responseHeaders.find(h => h.name.toLowerCase() === 'content-type'); + const isText = h && isContentTypeText(h.value); + tabMan.set(tabId, isContentTypeText.name, isText); + if (isText) { + openInstallerPage(tabId, url, {}); + // Silently suppress navigation. + // Don't redirect to the install URL as it'll flash the text! + return {cancel: true}; } +} - async function openInstallerPage(tabId, url, {code, inTab} = {}) { - const newUrl = makeInstallerUrl(url); - if (inTab) { - const tab = await browser.tabs.get(tabId); - return openURL({ - url: `${newUrl}&tabId=${tabId}`, - active: tab.active, - index: tab.index + 1, - openerTabId: tabId, - currentWindow: null, - }); - } - const timer = setTimeout(clearInstallCode, 10e3, url); - installCodeCache[url] = {code, timer}; - try { - await browser.tabs.update(tabId, {url: newUrl}); - } catch (err) { - // FIXME: remove this when kiwi supports tabs.update - // https://github.com/openstyles/stylus/issues/1367 - if (/Tabs cannot be edited right now/i.test(err.message)) { - return browser.tabs.create({url: newUrl}); - } - throw err; +async function openInstallerPage(tabId, url, {code, inTab} = {}) { + const newUrl = makeInstallerUrl(url); + if (inTab) { + const tab = await browser.tabs.get(tabId); + return openURL({ + url: `${newUrl}&tabId=${tabId}`, + active: tab.active, + index: tab.index + 1, + openerTabId: tabId, + currentWindow: null, + }); + } + const timer = setTimeout(clearInstallCode, 10e3, url); + installCodeCache[url] = {code, timer}; + try { + await browser.tabs.update(tabId, {url: newUrl}); + } catch (err) { + // FIXME: remove this when kiwi supports tabs.update + // https://github.com/openstyles/stylus/issues/1367 + if (/Tabs cannot be edited right now/i.test(err.message)) { + return browser.tabs.create({url: newUrl}); } + throw err; } -}); +} diff --git a/src/background/usercss-manager.js b/src/background/usercss-manager.js index ec996a398a3..550d25cf3df 100644 --- a/src/background/usercss-manager.js +++ b/src/background/usercss-manager.js @@ -1,154 +1,149 @@ -/* global API */// msg.js -/* global download */// common.js -/* global RX_META UCD deepCopy mapObj */// toolbox.js -/* global styleMan */ -'use strict'; +import {deepCopy, mapObj, RX_META, UCD} from '/js/toolbox'; +import {API} from './common'; +import download from './download'; +import * as styleMan from './style-manager'; -const usercssMan = { +const GLOBAL_META = Object.entries({ + author: null, + description: null, + homepageURL: 'url', + updateURL: 'updateUrl', + name: null, +}); - GLOBAL_META: Object.entries({ - author: null, - description: null, - homepageURL: 'url', - updateURL: 'updateUrl', - name: null, - }), - - /** `src` is a style or vars */ - async assignVars(style, src) { - const meta = style[UCD]; - const meta2 = src[UCD]; - const {vars} = meta; - const oldVars = meta2 ? meta2.vars : src; - if (vars && oldVars) { - // The type of var might be changed during the update. Set value to null if the value is invalid. - for (const [key, v] of Object.entries(vars)) { - const old = oldVars[key] && oldVars[key].value; - if (old != null) v.value = old; - } - meta.vars = await API.worker.nullifyInvalidVars(vars); +/** `src` is a style or vars */ +export async function assignVars(style, src) { + const meta = style[UCD]; + const meta2 = src[UCD]; + const {vars} = meta; + const oldVars = meta2 ? meta2.vars : src; + if (vars && oldVars) { + // The type of var might be changed during the update. Set value to null if the value is invalid. + for (const [key, v] of Object.entries(vars)) { + const old = oldVars[key] && oldVars[key].value; + if (old != null) v.value = old; } - }, + meta.vars = await API.worker.nullifyInvalidVars(vars); + } +} - async build({ - styleId, - sourceCode, - vars, - checkDup, - metaOnly, - assignVars, - initialUrl, - }) { - // downloading here while install-usercss page is loading to avoid the wait - if (initialUrl) sourceCode = await download(initialUrl); - const style = await usercssMan.buildMeta({sourceCode}); - const dup = (checkDup || assignVars) && - usercssMan.find(styleId ? {id: styleId} : style); - let log; - if (!metaOnly) { - if (vars || assignVars) { - await usercssMan.assignVars(style, vars || dup); - } - await usercssMan.buildCode(style); - log = style.log; // extracting the non-enumerable prop, otherwise it won't survive messaging +export async function build({ + styleId, + sourceCode, + vars, + checkDup, + metaOnly, + assignVars, + initialUrl, +}) { + // downloading here while install-usercss page is loading to avoid the wait + if (initialUrl) sourceCode = await download(initialUrl); + const style = await buildMeta({sourceCode}); + const dup = (checkDup || assignVars) && + find(styleId ? {id: styleId} : style); + let log; + if (!metaOnly) { + if (vars || assignVars) { + await assignVars(style, vars || dup); } - return {style, dup, log}; - }, + await buildCode(style); + log = style.log; // extracting the non-enumerable prop, otherwise it won't survive messaging + } + return {style, dup, log}; +} - async buildCode(style) { - const {sourceCode: code, [UCD]: {vars, preprocessor}} = style; - const {sections, errors, log} = await API.worker.compileUsercss(preprocessor, code, vars); - const recoverable = errors.every(e => e.recoverable); - if (!sections.length || !recoverable) { - throw !recoverable ? errors : 'Style does not contain any actual CSS to apply.'; - } - style.sections = sections; - // adding a non-enumerable prop so it won't be written to storage - if (log) Object.defineProperty(style, 'log', {value: log}); - return style; - }, +export async function buildCode(style) { + const {sourceCode: code, [UCD]: {vars, preprocessor}} = style; + const {sections, errors, log} = await API.worker.compileUsercss(preprocessor, code, vars); + const recoverable = errors.every(e => e.recoverable); + if (!sections.length || !recoverable) { + throw !recoverable ? errors : 'Style does not contain any actual CSS to apply.'; + } + style.sections = sections; + // adding a non-enumerable prop so it won't be written to storage + if (log) Object.defineProperty(style, 'log', {value: log}); + return style; +} - async buildMeta(style) { - if (style[UCD]) { - return style; - } - // remember normalized sourceCode - const code = style.sourceCode = style.sourceCode.replace(/\r\n?/g, '\n'); - style = Object.assign({ - enabled: true, - sections: [], - }, style); - const match = code.match(RX_META); - if (!match) { - return Promise.reject(new Error('Could not find metadata.')); - } - try { - const {metadata} = await API.worker.parseUsercssMeta(match[0]); - style[UCD] = metadata; - // https://github.com/openstyles/stylus/issues/560#issuecomment-440561196 - for (const [key, globalKey] of usercssMan.GLOBAL_META) { - const val = metadata[key]; - if (val !== undefined) { - style[globalKey || key] = val; - } - } - return style; - } catch (err) { - if (err.code) { - const args = err.code === 'missingMandatory' || err.code === 'missingChar' - ? err.args.map(e => e.length === 1 ? JSON.stringify(e) : e).join(', ') - : err.args; - const msg = chrome.i18n.getMessage(`meta_${(err.code)}`, args); - if (msg) err.message = msg; - err.index += match.index; +export async function buildMeta(style) { + if (style[UCD]) { + return style; + } + // remember normalized sourceCode + const code = style.sourceCode = style.sourceCode.replace(/\r\n?/g, '\n'); + style = Object.assign({ + enabled: true, + sections: [], + }, style); + const match = code.match(RX_META); + if (!match) { + return Promise.reject(new Error('Could not find metadata.')); + } + try { + const {metadata} = await API.worker.parseUsercssMeta(match[0]); + style[UCD] = metadata; + // https://github.com/openstyles/stylus/issues/560#issuecomment-440561196 + for (const [key, globalKey] of GLOBAL_META) { + const val = metadata[key]; + if (val !== undefined) { + style[globalKey || key] = val; } - return Promise.reject(err); } - }, + return style; + } catch (err) { + if (err.code) { + const args = err.code === 'missingMandatory' || err.code === 'missingChar' + ? err.args.map(e => e.length === 1 ? JSON.stringify(e) : e).join(', ') + : err.args; + const msg = chrome.i18n.getMessage(`meta_${(err.code)}`, args); + if (msg) err.message = msg; + err.index += match.index; + } + return Promise.reject(err); + } +} - async configVars(id, vars) { - const style = deepCopy(styleMan.get(id)); - style[UCD].vars = vars; - await usercssMan.buildCode(style); - return (await styleMan.install(style, 'config'))[UCD].vars; - }, +export async function configVars(id, vars) { + const style = deepCopy(styleMan.get(id)); + style[UCD].vars = vars; + await buildCode(style); + return (await API.styles.install(style, 'config'))[UCD].vars; +} - async editSave(style) { - style = await usercssMan.parse(style); - return { - log: style.log, // extracting the non-enumerable prop, otherwise it won't survive messaging - style: await styleMan.editSave(style), - }; - }, +export async function editSave(style) { + style = await parse(style); + return { + log: style.log, // extracting the non-enumerable prop, otherwise it won't survive messaging + style: await styleMan.editSave(style), + }; +} - /** - * @param {Object} data - style object or usercssData - * @return {StyleObj|void} - */ - find(data) { - if (data.id) return styleMan.get(data.id); - const filter = mapObj(data[UCD] || data, null, ['name', 'namespace']); - return styleMan.find(filter, UCD); - }, +/** + * @param {Object} data - style object or usercssData + * @return {StyleObj|void} + */ +export function find(data) { + if (data.id) return styleMan.get(data.id); + const filter = mapObj(data[UCD] || data, null, ['name', 'namespace']); + return styleMan.find(filter, UCD); +} - getVersion(data) { - const s = usercssMan.find(data); - return s && s[UCD].version; - }, +export function getVersion(data) { + return find(data)?.[UCD].version; +} - async install(style, opts) { - return styleMan.install(await usercssMan.parse(style, opts)); - }, +export async function install(style, opts) { + return styleMan.install(await parse(style, opts)); +} - async parse(style, {dup, vars} = {}) { - style = await usercssMan.buildMeta(style); - // preserve style.vars during update - if (dup || (dup = usercssMan.find(style))) { - style.id = dup.id; - } - if (vars || (vars = dup)) { - await usercssMan.assignVars(style, vars); - } - return usercssMan.buildCode(style); - }, -}; +export async function parse(style, {dup, vars} = {}) { + style = await buildMeta(style); + // preserve style.vars during update + if (dup || (dup = find(style))) { + style.id = dup.id; + } + if (vars || (vars = dup)) { + await assignVars(style, vars); + } + return buildCode(style); +} diff --git a/src/background/uso-api.js b/src/background/uso-api.js index 7798b1a12bb..02d13d97646 100644 --- a/src/background/uso-api.js +++ b/src/background/uso-api.js @@ -1,122 +1,117 @@ -/* global API */// msg.js -/* global RX_META UCD URLS */// toolbox.js -/* global download */// common.js -/* global styleMan */ -/* global usercssMan */ -'use strict'; +import {fetchText, RX_META, UCD, URLS} from '/js/toolbox'; +import {API} from './common'; +import download from './download'; +import * as styleMan from './style-manager'; -const usoApi = (() => { - const pingers = {}; - const getMd5Url = usoId => `https://update.userstyles.org/${usoId}.md5`; - return { +const pingers = {}; +const getMd5Url = usoId => `https://update.userstyles.org/${usoId}.md5`; - delete(usoId) { - const style = findStyle(usoId); - return style ? styleMan.delete(style.id) : false; - }, +export function deleteStyle(usoId) { + const style = findStyle(usoId); + return style ? styleMan.remove(style.id) : false; +} - /** UserCSS metadata may be embedded in the original USO style so let's use its updateURL */ - getEmbeddedMeta(code) { - const isRaw = arguments[0]; - const m = code.includes('@updateURL') && (isRaw ? code : code.replace(RX_META, '')).match(RX_META); - return m && API.usercss.buildMeta({sourceCode: m[0]}).catch(() => null); - }, +/** UserCSS metadata may be embedded in the original USO style so let's use its updateURL */ +export function getEmbeddedMeta(code) { + const isRaw = arguments[0]; + const m = code.includes('@updateURL') + && (isRaw ? code : code.replace(RX_META, '')).match(RX_META); + return m && API.usercss.buildMeta({sourceCode: m[0]}).catch(() => null); +} - async getUpdatability(usoId, asObject) { - const md5Url = getMd5Url(usoId); - const md5 = await (await fetch(md5Url)).text(); - const dup = await findStyle(usoId, md5Url); - // see STATE_EVENTS in install-hook-userstyles.js - const state = !dup ? 0 : dup[UCD] || dup.originalMd5 === md5 ? 2 : 1; - return asObject - ? {dup, md5, md5Url, state} - : state; - }, +export async function getUpdatability(usoId, asObject) { + const md5Url = getMd5Url(usoId); + const md5 = await fetchText(md5Url); + const dup = await findStyle(usoId, md5Url); + // see STATE_EVENTS in install-hook-userstyles.js + const state = !dup ? 0 : dup[UCD] || dup.originalMd5 === md5 ? 2 : 1; + return asObject + ? {dup, md5, md5Url, state} + : state; +} - pingback(usoId, delay) { - clearTimeout(pingers[usoId]); - delete pingers[usoId]; - if (delay > 0) { - return new Promise(resolve => (pingers[usoId] = setTimeout(ping, delay, usoId, resolve))); - } else if (delay !== false) { - return ping(usoId); - } - }, +export function pingback(usoId, delay) { + clearTimeout(pingers[usoId]); + delete pingers[usoId]; + if (delay > 0) { + return new Promise(resolve => (pingers[usoId] = setTimeout(ping, delay, usoId, resolve))); + } else if (delay !== false) { + return ping(usoId); + } +} - /** - * Replicating USO-Archive format - */ - async toUsercss(usoId, varsUrl, css, dup, md5, md5Url) { - let v; - if (!dup) dup = false; // "polyfilling" for dup?.prop - const {updateUrl = URLS.makeUpdateUrl('usoa', usoId)} = dup; - const jobs = [ - !dup && usoApi.getUpdatability(usoId, true).then(res => ({dup, md5, md5Url} = res)), - !css && download(updateUrl).then(res => (css = res)), - ].filter(Boolean); - if (jobs[0]) await Promise.all(jobs); - const varMap = {}; - const {style} = await usercssMan.build({sourceCode: css, metaOnly: true}); - const vars = (v = varsUrl || dup.updateUrl) && useVars(style, v, varMap); - if (dup) { - return style; - } - style.md5Url = md5Url; - style.originalMd5 = md5; - style.updateUrl = updateUrl; - await API.usercss.install(style, {dup, vars}); - }, - }; +/** + * Replicating USO-Archive format + */ +export async function toUsercss(usoId, varsUrl, css, dup, md5, md5Url) { + let v; + if (!dup) dup = false; // "polyfilling" for dup?.prop + const {updateUrl = URLS.makeUpdateUrl('usoa', usoId)} = dup; + const jobs = [ + !dup && getUpdatability(usoId, true).then(res => ({dup, md5, md5Url} = res)), + !css && download(updateUrl).then(res => (css = res)), + ].filter(Boolean); + if (jobs[0]) await Promise.all(jobs); + const varMap = {}; + const {style} = await API.usercss.build({sourceCode: css, metaOnly: true}); + const vars = (v = varsUrl || dup.updateUrl) && useVars(style, v, varMap); + if (dup) { + return style; + } + style.md5Url = md5Url; + style.originalMd5 = md5; + style.updateUrl = updateUrl; + await API.usercss.install(style, {dup, vars}); +} - function useVars(style, src, cfg) { - src = typeof src === 'string' - ? new URLSearchParams(src.split('?')[1]) - : Object.entries(src); - const {vars} = style[UCD]; - if (!vars) { - return; - } - for (let [key, val] of src) { - if (!key.startsWith('ik-')) continue; - key = makeKey(key.slice(3), cfg); - const v = vars[key]; - if (!v) continue; - if (v.options) { - let sel = val.startsWith('ik-') && optByName(v, makeKey(val.slice(3), cfg)); - if (!sel) { - key += '-custom'; - sel = optByName(v, key + '-dropdown'); - if (sel) vars[key].value = val; - } - if (sel) v.value = sel.name; - } else { - v.value = val; +function useVars(style, src, cfg) { + src = typeof src === 'string' + ? new URLSearchParams(src.split('?')[1]) + : Object.entries(src); + const {vars} = style[UCD]; + if (!vars) { + return; + } + for (let [key, val] of src) { + if (!key.startsWith('ik-')) continue; + key = makeKey(key.slice(3), cfg); + const v = vars[key]; + if (!v) continue; + if (v.options) { + let sel = val.startsWith('ik-') && optByName(v, makeKey(val.slice(3), cfg)); + if (!sel) { + key += '-custom'; + sel = optByName(v, key + '-dropdown'); + if (sel) vars[key].value = val; } + if (sel) v.value = sel.name; + } else { + v.value = val; } - return style; } + return style; +} - function findStyle(usoId, md5Url = getMd5Url(usoId)) { - return styleMan.find({md5Url}) - || styleMan.find({installationUrl: URLS.makeInstallUrl('usoa', usoId)}); - } +function findStyle(usoId, md5Url = getMd5Url(usoId)) { + return styleMan.find({md5Url}) + || styleMan.find({installationUrl: URLS.makeInstallUrl('usoa', usoId)}); +} - async function ping(id, resolve) { - await fetch(`${URLS.uso}styles/install/${id}?source=stylish-ch`); - if (resolve) resolve(true); - return true; - } +async function ping(id, resolve) { + await fetch(`${URLS.uso}styles/install/${id}?source=stylish-ch`); + if (resolve) resolve(true); + return true; +} - function makeKey(key, varMap) { - let res = varMap[key]; - if (!res && key !== (res = key.replace(/[^-\w]/g, '-'))) { - while (res in varMap) res += '-'; - varMap[key] = res; - } - return res; +function makeKey(key, varMap) { + let res = varMap[key]; + if (!res && key !== (res = key.replace(/[^-\w]/g, '-'))) { + while (res in varMap) res += '-'; + varMap[key] = res; } + return res; +} - function optByName(v, name) { - return v.options.find(o => o.name === name); - } -})(); +function optByName(v, name) { + return v.options.find(o => o.name === name); +} diff --git a/src/background/usw-api.js b/src/background/usw-api.js index a0f4cb27750..e49d3ff3baf 100644 --- a/src/background/usw-api.js +++ b/src/background/usw-api.js @@ -1,133 +1,120 @@ -/* global API msg */// msg.js -/* global UCD URLS RX_META deepEqual mapObj tryURL */// toolbox.js -/* global styleMan */ -/* global tokenMan */ -'use strict'; +import {deepEqual, mapObj, RX_META, tryURL, UCD, URLS} from '/js/toolbox'; +import {broadcastExtension} from './broadcast'; +import {API} from './common'; +import * as styleMan from './style-manager'; +import {getToken, revokeToken} from './token-manager'; -const uswApi = (() => { +const KEYS_OUT = ['description', 'homepage', 'license', 'name']; +const KEYS_IN = [...KEYS_OUT, 'id', 'namespace', 'username']; +const pushId = id => API.data.set('usw' + id, true); +const popId = id => API.data.del('usw' + id); - //#region Internals - - const KEYS_OUT = ['description', 'homepage', 'license', 'name']; - const KEYS_IN = [...KEYS_OUT, 'id', 'namespace', 'username']; - - class TokenHooks { - constructor(id) { - this.id = id; - } - keyName(name) { - return `${name}/${this.id}`; - } - query(query) { - return Object.assign(query, {vendor_data: this.id}); - } +class TokenHooks { + constructor(id) { + this.id = id; } - - function fakeUsercssHeader(style, usw) { - const {namespace: ns, username: user} = usw || (usw = {}); - const meta = [ - 'name', - // Same as USO-archive version: YYYYMMDD.hh.mm - ['@version', new Date().toISOString().replace(/^(\d+)-(\d+)-(\d+)T(\d+):(\d+).+/, '$1$2$3.$4.$5')], - ['@namespace', ns !== '?' && ns || - user && `https://userstyles.world/user/${user}` || - '?'], - 'description', - ['@homepage', tryURL(ns).href], - ['@author', user], - 'license', - ].map((k, _) => k.map ? k[1] && k : (_ = usw[k] || style[k]) && ['@' + k, _]).filter(Boolean); - const maxKeyLen = meta.reduce((res, [k]) => Math.max(res, k.length), 0); - return '/* ==UserStyle==\n' + - meta.map(([k, v]) => `${k}${' '.repeat(maxKeyLen - k.length + 2)}${v}\n`).join('') + - '==/UserStyle== */\n\n'; + keyName(name) { + return `${name}/${this.id}`; } - - async function linkStyle(style, sourceCode) { - const {id, name} = style; - const {metadata} = await API.worker.parseUsercssMeta(sourceCode.match(RX_META)[0]); - const out = {name, sourceCode, [UCD]: {}}; - const KEY = 'usw' + id; - for (const k of KEYS_OUT) out[k] = out[UCD][k] = metadata[k] || ''; - API.data.set(KEY, out); - try { - const token = await tokenMan.getToken('userstylesworld', true, new TokenHooks(id)); - const info = await uswFetch('style', token); - const data = mapObj(info, null, style[UCD] ? ['id'] : KEYS_IN); - data.token = token; - style.url = style.url || info.homepage || `${URLS.usw}style/${data.id}`; - return data; - } finally { - API.data.del(KEY); - } + query(query) { + return Object.assign(query, {vendor_data: this.id}); } +} - async function uswFetch(path, token, opts) { - opts = Object.assign({credentials: 'omit'}, opts); - opts.headers = Object.assign({Authorization: `Bearer ${token}`}, opts.headers); - return (await (await fetch(`${URLS.usw}api/${path}`, opts)).json()).data; - } +function fakeUsercssHeader(style, usw) { + const {namespace: ns, username: user} = usw || (usw = {}); + const meta = [ + 'name', + // Same as USO-archive version: YYYYMMDD.hh.mm + ['@version', new Date().toISOString().replace(/^(\d+)-(\d+)-(\d+)T(\d+):(\d+).+/, '$1$2$3.$4.$5')], + ['@namespace', ns !== '?' && ns || + user && `https://userstyles.world/user/${user}` || + '?'], + 'description', + ['@homepage', tryURL(ns).href], + ['@author', user], + 'license', + ].map((k, _) => k.map ? k[1] && k : (_ = usw[k] || style[k]) && ['@' + k, _]).filter(Boolean); + const maxKeyLen = meta.reduce((res, [k]) => Math.max(res, k.length), 0); + return '/* ==UserStyle==\n' + + meta.map(([k, v]) => `${k}${' '.repeat(maxKeyLen - k.length + 2)}${v}\n`).join('') + + '==/UserStyle== */\n\n'; +} - /** Uses a custom method when broadcasting and avoids needlessly sending the entire style */ - async function uswSave(style, _usw) { - const {id} = style; - if (_usw) style._usw = _usw; - await styleMan.save(style, {broadcast: false}); - msg.broadcastExtension({method: 'uswData', style: {id, _usw}}); +async function linkStyle(style, sourceCode) { + const {id, name} = style; + const {metadata} = await API.worker.parseUsercssMeta(sourceCode.match(RX_META)[0]); + const out = {name, sourceCode, [UCD]: {}}; + const KEY = 'usw' + id; + for (const k of KEYS_OUT) out[k] = out[UCD][k] = metadata[k] || ''; + API.data.set(KEY, out); + try { + const token = await getToken('userstylesworld', true, new TokenHooks(id)); + const info = await uswFetch('style', token); + const data = mapObj(info, null, style[UCD] ? ['id'] : KEYS_IN); + data.token = token; + style.url = style.url || info.homepage || `${URLS.usw}style/${data.id}`; + return data; + } finally { + API.data.del(KEY); } +} - //#endregion - //#region Exports - - return { - /** - * @param {number} id - * @param {string} code - * @param {USWorldData} [usw] - * @return {Promise} - */ - async publish(id, code, usw) { - const style = styleMan.get(id); - if (!usw) usw = style._usw; - if (!style[UCD]) code = fakeUsercssHeader(style, usw) + code; - if (!usw || !usw.token || !usw.id) usw = await linkStyle(style, code); - const res = await uswFetch(`style/${usw.id}`, usw.token, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({code}), - }); - if (!deepEqual(usw, style._usw)) { - await uswSave(style, usw); - } - return res; - }, +async function uswFetch(path, token, opts) { + opts = Object.assign({credentials: 'omit'}, opts); + opts.headers = Object.assign({Authorization: `Bearer ${token}`}, opts.headers); + return (await (await fetch(`${URLS.usw}api/${path}`, opts)).json()).data; +} - /** - * @param {number} id - * @return {Promise} - */ - async revoke(id) { - await tokenMan.revokeToken('userstylesworld', new TokenHooks(id)); - const style = styleMan.get(id); - if (style) { - delete style._usw.token; - await uswSave(style); - } - }, - }; +/** Uses a custom method when broadcasting and avoids needlessly sending the entire style */ +async function uswSave(style, _usw) { + const {id} = style; + if (_usw) style._usw = _usw; + await styleMan.save(style, {broadcast: false}); + broadcastExtension({method: 'uswData', style: {id, _usw}}); +} - //#endregion -})(); +/** + * @param {number} id + * @param {string} code + * @param {USWorldData} [usw] + * @return {Promise} + */ +export async function publish(id, code, usw) { + try { + pushId(id); + const style = styleMan.get(id); + if (!usw) usw = style._usw; + if (!style[UCD]) code = fakeUsercssHeader(style, usw) + code; + if (!usw || !usw.token || !usw.id) usw = await linkStyle(style, code); + const res = await uswFetch(`style/${usw.id}`, usw.token, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({code}), + }); + if (!deepEqual(usw, style._usw)) { + await uswSave(style, usw); + } + return res; + } finally { + popId(id); + } +} -/* Doing this outside so we don't break IDE's recognition of the exported methods in IIFE */ -for (const [k, fn] of Object.entries(uswApi)) { - uswApi[k] = async (id, ...args) => { +/** + * @param {number} id + * @return {Promise} + */ +export async function revoke(id) { + try { API.data.set('usw' + id, true); - try { - /* Awaiting inside `try` so that `finally` runs when done */ - return await fn(id, ...args); - } finally { - API.data.del('usw' + id); + await revokeToken('userstylesworld', new TokenHooks(id)); + const style = styleMan.get(id); + if (style) { + delete style._usw.token; + await uswSave(style); } - }; + } finally { + API.data.del('usw' + id); + } } diff --git a/src/content/apply.js b/src/content/apply.js index 44a4c63dea2..6883bef29d8 100644 --- a/src/content/apply.js +++ b/src/content/apply.js @@ -1,288 +1,298 @@ -/* global API msg */// msg.js -/* global StyleInjector isFrame isFrameNoUrl isFrameSameOrigin */// style-injector.js -/* global TDM:true */// style-injector.js -'use strict'; - -(() => { - if (window.INJECTED === 1) return; - window.INJECTED = 1; - - let isTab = !chrome.tabs || location.pathname !== '/popup.html'; - const own = /** @type {Injection} */{ - cfg: {off: false, top: ''}, - }; - const calcOrder = ({id}, _) => - (_ = own.cfg.order) && - (_.prio[id] || 0) * 1e6 || - _.main[id] || - id + .5e6; // no order = at the end of `main` - const isXml = document instanceof XMLDocument; - const CHROME = 'app' in chrome; - const SYM_ID = 'styles'; - const isUnstylable = !CHROME && isXml; - const styleInjector = StyleInjector({ - compare: (a, b) => calcOrder(a) - calcOrder(b), - onUpdate: onInjectorUpdate, - }); - const clone = typeof deepCopy === 'function' - ? deepCopy /* global deepCopy */// will be used in extension context - : val => typeof val === 'object' && val ? JSON.parse(JSON.stringify(val)) : val; - // dynamic iframes don't have a URL yet so we'll use their parent's URL (hash isn't inherited) - let matchUrl = isFrameNoUrl - ? parent.location.href.split('#')[0] - : location.href; - let isOrphaned, orphanCleanup; - let offscreen; - // firefox doesn't orphanize content scripts so the old elements stay - if (!CHROME) styleInjector.clearOrphans(); - - /** @type chrome.runtime.Port */ - let port; - let lazyBadge = isFrame; - - /** Polyfill for documentId in Firefox and Chrome pre-106 */ - const instanceId = !(CHROME && CSS.supports('top', '1ic')) && (Math.random() + matchUrl); - /* about:blank iframes are often used by sites for file upload or background tasks - * and they may break if unexpected DOM stuff is present at `load` event - * so we'll add the styles only if the iframe becomes visible */ - const xoEventId = `${Math.random()}`; - /** @type IntersectionObserver */ - let xo; - window[Symbol.for('xo')] = (el, cb) => { - if (!xo) xo = new IntersectionObserver(onIntersect, {rootMargin: '100%'}); - el.addEventListener(xoEventId, cb, {once: true}); - xo.observe(el); +import * as msg from '/js/msg-base'; +import {API, apiPortDisconnect} from '/js/msg-base'; +import StyleInjector from './style-injector'; + +// TODO: handle INJECTED = 1 in rollup? + +let isTab = !chrome.tabs || location.pathname !== '/popup.html'; +const own = /** @type {Injection} */{ + cfg: {off: false, top: ''}, +}; +const calcOrder = ({id}, _) => + (_ = own.cfg.order) && + (_.prio[id] || 0) * 1e6 || + _.main[id] || + id + .5e6; // no order = at the end of `main` +const isXml = document instanceof XMLDocument; +const CHROME = 'app' in chrome; +const SYM_ID = 'styles'; +const isUnstylable = !CHROME && isXml; +const styleInjector = StyleInjector({ + compare: (a, b) => calcOrder(a) - calcOrder(b), + onUpdate: onInjectorUpdate, +}); +const clone = __ENTRY !== 'content' + ? deepCopy /* global deepCopy */// will be used in extension context + : val => typeof val === 'object' && val ? JSON.parse(JSON.stringify(val)) : val; +const isFrame = window !== parent; +/** @type {number} + * TODO: expose to msg.js without `window` + * -1 = top prerendered, 0 = iframe, 1 = top, 2 = top reified */ +let TDM = window.TDM = isFrame ? 0 : document.prerendering ? -1 : 1; +let isFrameSameOrigin = false; +if (isFrame) { + try { + isFrameSameOrigin = Object.getOwnPropertyDescriptor(parent.location, 'href'); + isFrameSameOrigin = !!isFrameSameOrigin?.get; + } catch (e) {} +} +const isFrameNoUrl = isFrameSameOrigin && location.protocol === 'about:'; + +// dynamic iframes don't have a URL yet so we'll use their parent's URL (hash isn't inherited) +let matchUrl = isFrameNoUrl + ? parent.location.href.split('#')[0] + : location.href; +let isOrphaned, orphanCleanup; +let offscreen; +// firefox doesn't orphanize content scripts so the old elements stay +if (!CHROME) styleInjector.clearOrphans(); + +/** @type chrome.runtime.Port */ +let port; +let lazyBadge = isFrame; + +/** Polyfill for documentId in Firefox and Chrome pre-106 */ +const instanceId = !(CHROME && CSS.supports('top', '1ic')) && (Math.random() + matchUrl); +/* about:blank iframes are often used by sites for file upload or background tasks + * and they may break if unexpected DOM stuff is present at `load` event + * so we'll add the styles only if the iframe becomes visible */ +const xoEventId = `${Math.random()}`; +/** @type IntersectionObserver */ +let xo; +window[Symbol.for('xo')] = (el, cb) => { + if (!xo) xo = new IntersectionObserver(onIntersect, {rootMargin: '100%'}); + el.addEventListener(xoEventId, cb, {once: true}); + xo.observe(el); +}; + +// FIXME: move this to background page when following bugs are fixed: +// https://bugzil.la/1587723, https://crbug.com/968651 +const mqDark = !isFrame && matchMedia('(prefers-color-scheme: dark)'); +if (mqDark) { + mqDark.onchange = ({matches: m}) => { + if (m !== own.cfg.dark) API.info.set({preferDark: own.cfg.dark = m}); }; +} - // FIXME: move this to background page when following bugs are fixed: - // https://bugzil.la/1587723, https://crbug.com/968651 - const mqDark = !isFrame && matchMedia('(prefers-color-scheme: dark)'); - if (mqDark) { - mqDark.onchange = ({matches: m}) => { - if (m !== own.cfg.dark) API.info.set({preferDark: own.cfg.dark = m}); - }; - } +// Declare all vars before init() or it'll throw due to "temporal dead zone" of const/let +init(); - // Declare all vars before init() or it'll throw due to "temporal dead zone" of const/let - init(); +// the popup needs a check as it's not a tab but can be opened in a tab manually for whatever reason +if (!isTab) { + chrome.tabs.getCurrent(tab => { + isTab = Boolean(tab); + if (tab && styleInjector.list.length) updateCount(); + }); +} - // the popup needs a check as it's not a tab but can be opened in a tab manually for whatever reason - if (!isTab) { - chrome.tabs.getCurrent(tab => { - isTab = Boolean(tab); - if (tab && styleInjector.list.length) updateCount(); - }); - } +msg.onTab(applyOnMessage); +addEventListener('pageshow', onBFCache); +addEventListener('pagehide', onBFCache); +if (TDM < 0) document.onprerenderingchange = onReified; - msg.onTab(applyOnMessage); - addEventListener('pageshow', onBFCache); - addEventListener('pagehide', onBFCache); - if (TDM < 0) document.onprerenderingchange = onReified; +if (!chrome.tabs) { + dispatchEvent(new CustomEvent(chrome.runtime.id, {detail: orphanCleanup = Math.random()})); + addEventListener(chrome.runtime.id, orphanCheck, true); +} - if (!chrome.tabs) { - dispatchEvent(new CustomEvent(chrome.runtime.id, {detail: orphanCleanup = Math.random()})); - addEventListener(chrome.runtime.id, orphanCheck, true); +function onInjectorUpdate() { + if (!isOrphaned) { + updateCount(); + if (isFrame) updateExposeIframes(); } +} - function onInjectorUpdate() { - if (!isOrphaned) { - updateCount(); - if (isFrame) updateExposeIframes(); - } +async function init() { + if (isUnstylable) return API.styleViaAPI({method: 'styleApply'}); + let data = isFrameNoUrl && CHROME && clone(parent[parent.Symbol.for(SYM_ID)]); + if (data) await new Promise(onFrameElementInView); + else data = !isFrameSameOrigin && !isXml && !chrome.tabs && tryCatch(getStylesViaXhr); + // XML in Chrome will be auto-converted to html later, so we can't style it via XHR now + await applyStyles(data); + if (orphanCleanup) { + dispatchEvent(new Event(orphanCleanup)); + orphanCleanup = false; } +} - async function init() { - if (isUnstylable) return API.styleViaAPI({method: 'styleApply'}); - let data = isFrameNoUrl && CHROME && clone(parent[parent.Symbol.for(SYM_ID)]); - if (data) await new Promise(onFrameElementInView); - else data = !isFrameSameOrigin && !isXml && !chrome.tabs && tryCatch(getStylesViaXhr); - // XML in Chrome will be auto-converted to html later, so we can't style it via XHR now - await applyStyles(data); - if (orphanCleanup) { - dispatchEvent(new Event(orphanCleanup)); - orphanCleanup = false; - } - } +async function applyStyles(data) { + if (isOrphaned) return; + if (!data) data = await API.styles.getSectionsByUrl(matchUrl, null, !own.sections); + if (!data.cfg) data.cfg = own.cfg; + Object.assign(own, window[Symbol.for(SYM_ID)] = data); + if (!isFrame && own.cfg.top === '') own.cfg.top = location.origin; // used by child frames via parentStyles + if (!isFrame && own.cfg.dark !== mqDark.matches) mqDark.onchange(mqDark); + if (styleInjector.list.length) styleInjector.replace(own); + else if (!own.cfg.off) styleInjector.apply(own); + styleInjector.toggle(!own.cfg.off); +} - async function applyStyles(data) { - if (isOrphaned) return; - if (!data) data = await API.styles.getSectionsByUrl(matchUrl, null, !own.sections); - if (!data.cfg) data.cfg = own.cfg; - Object.assign(own, window[Symbol.for(SYM_ID)] = data); - if (!isFrame && own.cfg.top === '') own.cfg.top = location.origin; // used by child frames via parentStyles - if (!isFrame && own.cfg.dark !== mqDark.matches) mqDark.onchange(mqDark); - if (styleInjector.list.length) styleInjector.replace(own); - else if (!own.cfg.off) styleInjector.apply(own); - styleInjector.toggle(!own.cfg.off); - } +/** Must be executed inside try/catch */ +function getStylesViaXhr() { + const blobId = (document.cookie.split(chrome.runtime.id + '=')[1] || '').split(';')[0]; + if (!blobId) return; // avoiding an exception so we don't spoil debugging in devtools + const url = 'blob:' + chrome.runtime.getURL(blobId); + document.cookie = `${chrome.runtime.id}=1; max-age=0; SameSite=Lax`; // remove our cookie + const xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); // synchronous + xhr.send(); + URL.revokeObjectURL(url); + return JSON.parse(xhr.response); +} - /** Must be executed inside try/catch */ - function getStylesViaXhr() { - const blobId = (document.cookie.split(chrome.runtime.id + '=')[1] || '').split(';')[0]; - if (!blobId) return; // avoiding an exception so we don't spoil debugging in devtools - const url = 'blob:' + chrome.runtime.getURL(blobId); - document.cookie = `${chrome.runtime.id}=1; max-age=0; SameSite=Lax`; // remove our cookie - const xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); // synchronous - xhr.send(); - URL.revokeObjectURL(url); - return JSON.parse(xhr.response); +function applyOnMessage(req) { + if (isUnstylable && /^(style|updateCount|urlChanged)/.test(req.method)) { + API.styleViaAPI(req); + return; } + const {style} = req; + switch (req.method) { + case 'ping': + return true; - function applyOnMessage(req) { - if (isUnstylable && /^(style|updateCount|urlChanged)/.test(req.method)) { - API.styleViaAPI(req); - return; - } - const {style} = req; - switch (req.method) { - case 'ping': - return true; + case 'styleDeleted': + styleInjector.remove(style.id); + break; - case 'styleDeleted': + case 'styleUpdated': + if (!own.sections && own.cfg.off) break; + if (style.enabled) { + API.styles.getSectionsByUrl(matchUrl, style.id).then(res => + res.sections.length + ? styleInjector.apply(res) + : styleInjector.remove(style.id)); + } else { styleInjector.remove(style.id); - break; - - case 'styleUpdated': - if (!own.sections && own.cfg.off) break; - if (style.enabled) { - API.styles.getSectionsByUrl(matchUrl, style.id).then(res => - res.sections.length - ? styleInjector.apply(res) - : styleInjector.remove(style.id)); - } else { - styleInjector.remove(style.id); - } - break; - - case 'styleAdded': - if ((own.sections || !own.cfg.off) && style.enabled) { - API.styles.getSectionsByUrl(matchUrl, style.id) - .then(styleInjector.apply); - } - break; - - case 'urlChanged': - if (req.iid === instanceId && matchUrl !== req.url) { - matchUrl = req.url; - if (own.sections) applyStyles(own.cfg.off && {}); - } - break; - - case 'updateCount': - updateCount(); - break; - - case 'injectorConfig': - updateConfig(req); - break; - - case 'backgroundReady': - // This may happen when reloading the background page without reloading the extension - if (own.sections) updateCount(); - return true; - } - } + } + break; - function updateConfig({cfg}) { - for (const k in cfg) { - const v = cfg[k]; - if (v === own.cfg[k]) continue; - if (k === 'top' && !isFrame) continue; - own.cfg[k] = v; - if (k === 'off') updateDisableAll(); - else if (k === 'order') styleInjector.sort(); - else if (k === 'top') updateExposeIframes(); - else styleInjector.config(own.cfg); - } - } + case 'styleAdded': + if ((own.sections || !own.cfg.off) && style.enabled) { + API.styles.getSectionsByUrl(matchUrl, style.id) + .then(styleInjector.apply); + } + break; - function updateDisableAll() { - if (isUnstylable) { - API.styleViaAPI({method: 'injectorConfig', cfg: {off: own.cfg.off}}); - } else if (!own.sections && !own.cfg.off) { - if (!offscreen) init(); - } else { - styleInjector.toggle(!own.cfg.off); - } - } + case 'urlChanged': + if (req.iid === instanceId && matchUrl !== req.url) { + matchUrl = req.url; + if (own.sections) applyStyles(own.cfg.off && {}); + } + break; - function updateExposeIframes() { - const attr = 'stylus-iframe'; - const el = document.documentElement; - if (!el) return; // got no styles so styleInjector didn't wait for - if (!own.cfg.top || !styleInjector.list.length) { - if (el.hasAttribute(attr)) el.removeAttribute(attr); - } else if (el.getAttribute(attr) !== own.cfg.top) { // Checking first to avoid DOM mutations - el.setAttribute(attr, own.cfg.top); - } + case 'updateCount': + updateCount(); + break; + + case 'injectorConfig': + updateConfig(req); + break; + + case 'backgroundReady': + // This may happen when reloading the background page without reloading the extension + if (own.sections) updateCount(); + return true; } +} - function updateCount() { - if (!isTab || TDM < 0) return; - if (isFrame) { - if (!port && styleInjector.list.length) { - port = chrome.runtime.connect({name: 'iframe'}); - } else if (port && !styleInjector.list.length) { - port.disconnect(); - port = null; - } - if (lazyBadge && performance.now() > 1000) lazyBadge = false; - } - if (isUnstylable) API.styleViaAPI({method: 'updateCount'}); - else API.updateIconBadge(styleInjector.list.map(style => style.id), {lazyBadge, iid: instanceId}); +function updateConfig({cfg}) { + for (const k in cfg) { + const v = cfg[k]; + if (v === own.cfg[k]) continue; + if (k === 'top' && !isFrame) continue; + own.cfg[k] = v; + if (k === 'off') updateDisableAll(); + else if (k === 'order') styleInjector.sort(); + else if (k === 'top') updateExposeIframes(); + else styleInjector.config(own.cfg); } +} - function onFrameElementInView(cb) { - parent[parent.Symbol.for('xo')](frameElement, cb); - (offscreen || (offscreen = [])).push(cb); +function updateDisableAll() { + if (isUnstylable) { + API.styleViaAPI({method: 'injectorConfig', cfg: {off: own.cfg.off}}); + } else if (!own.sections && !own.cfg.off) { + if (!offscreen) init(); + } else { + styleInjector.toggle(!own.cfg.off); } +} - /** @param {IntersectionObserverEntry[]} entries */ - function onIntersect(entries) { - for (const e of entries) { - if (e.intersectionRatio) { - xo.unobserve(e.target); - e.target.dispatchEvent(new Event(xoEventId)); - } - } +function updateExposeIframes() { + const attr = 'stylus-iframe'; + const el = document.documentElement; + if (!el) return; // got no styles so styleInjector didn't wait for + if (!own.cfg.top || !styleInjector.list.length) { + if (el.hasAttribute(attr)) el.removeAttribute(attr); + } else if (el.getAttribute(attr) !== own.cfg.top) { // Checking first to avoid DOM mutations + el.setAttribute(attr, own.cfg.top); } +} - function onBFCache(e) { - if (e.isTrusted && e.persisted) { - msg._disconnectApi(); - updateCount(); +function updateCount() { + if (!isTab || TDM < 0) return; + if (isFrame) { + if (!port && styleInjector.list.length) { + port = chrome.runtime.connect({name: 'iframe'}); + } else if (port && !styleInjector.list.length) { + port.disconnect(); + port = null; } + if (lazyBadge && performance.now() > 1000) lazyBadge = false; } + if (isUnstylable) API.styleViaAPI({method: 'updateCount'}); + else API.updateIconBadge(styleInjector.list.map(style => style.id), {lazyBadge, iid: instanceId}); +} - function onReified(e) { - if (e.isTrusted) { - TDM = 2; - document.onprerenderingchange = null; - API.styles.getSectionsByUrl('', 0, 'cfg').then(updateConfig); - updateCount(); +function onFrameElementInView(cb) { + parent[parent.Symbol.for('xo')](frameElement, cb); + (offscreen || (offscreen = [])).push(cb); +} + +/** @param {IntersectionObserverEntry[]} entries */ +function onIntersect(entries) { + for (const e of entries) { + if (e.intersectionRatio) { + xo.unobserve(e.target); + e.target.dispatchEvent(new Event(xoEventId)); } } +} - function tryCatch(func, ...args) { - try { - return func(...args); - } catch (e) {} +function onBFCache(e) { + if (e.isTrusted && e.persisted) { + apiPortDisconnect(); + updateCount(); } +} - function orphanCheck(evt) { - if (chrome.runtime.id) return; - // In Chrome content script is orphaned on an extension update/reload - // so we need to detach event listeners - removeEventListener(evt.type, orphanCheck, true); - removeEventListener('pageshow', onBFCache); - removeEventListener('pagehide', onBFCache); - if (mqDark) mqDark.onchange = null; - if (offscreen) for (const fn of offscreen) fn(); - if (TDM < 0) document.onprerenderingchange = null; - offscreen = null; - isOrphaned = true; - styleInjector.shutdown(evt.detail); - tryCatch(msg.off, applyOnMessage); +function onReified(e) { + if (e.isTrusted) { + TDM = window.TDM = 2; + document.onprerenderingchange = null; + API.styles.getSectionsByUrl('', 0, 'cfg').then(updateConfig); + updateCount(); } -})(); +} + +function tryCatch(func, ...args) { + try { + return func(...args); + } catch (e) {} +} + +function orphanCheck(evt) { + if (chrome.runtime.id) return; + // In Chrome content script is orphaned on an extension update/reload + // so we need to detach event listeners + removeEventListener(evt.type, orphanCheck, true); + removeEventListener('pageshow', onBFCache); + removeEventListener('pagehide', onBFCache); + if (mqDark) mqDark.onchange = null; + if (offscreen) for (const fn of offscreen) fn(); + if (TDM < 0) document.onprerenderingchange = null; + offscreen = null; + isOrphaned = true; + styleInjector.shutdown(evt.detail); + tryCatch(msg.off, applyOnMessage); +} diff --git a/src/content/install-hook-greasyfork.js b/src/content/install-hook-greasyfork.js index 430161df0ea..bd6b43fb325 100644 --- a/src/content/install-hook-greasyfork.js +++ b/src/content/install-hook-greasyfork.js @@ -1,5 +1,5 @@ /* global API */// msg.js -'use strict'; +'use strict'; // eslint-disable-line strict // onCommitted may fire twice // Note, we're checking against a literal `1`, not just `if (truthy)`, diff --git a/src/content/install-hook-usercss.js b/src/content/install-hook-usercss.js index 423523775af..ecaf69f2335 100644 --- a/src/content/install-hook-usercss.js +++ b/src/content/install-hook-usercss.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict'; // eslint-disable-line strict // preventing reregistration if reinjected by tabs.executeScript for whatever reason, just in case if (typeof window.oldCode !== 'string') { diff --git a/src/content/install-hook-userstyles.js b/src/content/install-hook-userstyles.js index c89c116bcad..d65ec6fc39f 100644 --- a/src/content/install-hook-userstyles.js +++ b/src/content/install-hook-userstyles.js @@ -1,5 +1,5 @@ /* global API */// msg.js -'use strict'; +'use strict'; // eslint-disable-line strict (() => { if (window.INJECTED_USO === 1) return; @@ -56,7 +56,7 @@ gesture = NaN; break; case 'deleteStylishStyle': { - if (isTrusted(data)) res = await API.uso.delete(getUsoId()); + if (isTrusted(data)) res = await API.uso.deleteStyle(getUsoId()); gesture = NaN; break; } diff --git a/src/content/install-hook-userstylesworld.js b/src/content/install-hook-userstylesworld.js index 0f7bd56547b..20ae8bec026 100644 --- a/src/content/install-hook-userstylesworld.js +++ b/src/content/install-hook-userstylesworld.js @@ -1,5 +1,5 @@ /* global API */// msg.js -'use strict'; +'use strict'; // eslint-disable-line strict if (window.USW !== 1) { window.USW = 1; // avoiding re-injection diff --git a/src/content/style-injector.js b/src/content/style-injector.js index 44058821527..fdd2d89c23b 100644 --- a/src/content/style-injector.js +++ b/src/content/style-injector.js @@ -1,17 +1,4 @@ -'use strict'; - -{ - let x; - window.isFrame = x = window !== parent; - /** @type {number} - * -1 = top prerendered, 0 = iframe, 1 = top, 2 = top reified */ - window.TDM = x ? 0 : document.prerendering ? -1 : 1; - if (x) try { x = !!(Object.getOwnPropertyDescriptor(parent.location, 'href') || {}).get; } catch (e) { x = false; } - window.isFrameSameOrigin = x; - window.isFrameNoUrl = x && location.protocol === 'about:'; -} - -window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({ +export default ({ compare, onUpdate = () => {}, }) => { diff --git a/src/edit.html b/src/edit.html index 1b68990a940..8df76429c89 100644 --- a/src/edit.html +++ b/src/edit.html @@ -5,66 +5,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - + - - + + diff --git a/src/edit/autocomplete.js b/src/edit/autocomplete.js index d43db6a9da4..ea916798850 100644 --- a/src/edit/autocomplete.js +++ b/src/edit/autocomplete.js @@ -1,14 +1,12 @@ -/* global CodeMirror */ -/* global cmFactory */ -/* global UCD debounce stringAsRegExpStr tryRegExp */// toolbox.js -/* global editor */ -/* global linterMan */ -/* global prefs */ -'use strict'; +import CodeMirror from 'codemirror'; +import {UCD, debounce, stringAsRegExpStr, tryRegExp} from '/js/toolbox'; +import editor from './editor'; +import linterMan from './linter-manager'; +import cmFactory from './codemirror-factory'; +import * as prefs from '/js/prefs'; -/* Registers 'hint' helper and 'autocompleteOnTyping' option in CodeMirror */ - -(() => { +/** Registers 'hint' helper and 'autocompleteOnTyping' option in CodeMirror */ +export default function Autocomplete() { const USO_VAR = 'uso-variable'; const USO_VALID_VAR = 'variable-3 ' + USO_VAR; const USO_INVALID_VAR = 'error ' + USO_VAR; @@ -288,4 +286,4 @@ function autocompletePicked(cm) { cm.state.autocompletePicked = true; } -})(); +} diff --git a/src/edit/base.js b/src/edit/base.js deleted file mode 100644 index 5d557feb931..00000000000 --- a/src/edit/base.js +++ /dev/null @@ -1,433 +0,0 @@ -/* global $$ $ setInputValue setupLivePrefs */// dom.js -/* global API */// msg.js -/* global CODEMIRROR_THEMES */ -/* global CodeMirror */ -/* global MozDocMapper */// sections-util.js -/* global chromeSync */// storage-util.js -/* global initBeautifyButton */// beautify.js -/* global prefs */ -/* global t */// localization.js -/* global UCD FIREFOX clipString debounce getOwnTab sessionStore tryJSONparse tryURL */// toolbox.js -'use strict'; - -/** - * @type Editor - * @namespace Editor - */ -const editor = { - style: null, - dirty: DirtyReporter(), - isUsercss: false, - isWindowed: false, - livePreview: LivePreview(), - livePreviewLazy: cb => debounce(cb, prefs.get('editor.livePreview.delay') * 1000), - /** @type {Set} */ - regexps: new Set(), - /** @type {'customName'|'name'} */ - nameTarget: 'name', - ppDemo: { - stylus: 'https://stylus-lang.com/try.html', - less: 'https://lesscss.org/less-preview/', - }, - saving: false, - scrollInfo: {}, - - cancel: () => location.assign('/manage.html'), - - updateClass() { - $.rootCL.toggle('is-new-style', !editor.style.id); - }, - - updateTheme(name) { - if (!CODEMIRROR_THEMES[name]) { - name = 'default'; - prefs.set('editor.theme', name); - } - $('#cm-theme').dataset.theme = name; - $('#cm-theme').textContent = CODEMIRROR_THEMES[name] || ''; - }, - - updateTitle(isDirty = editor.dirty.isDirty()) { - const {customName, name} = editor.style; - document.title = `${ - isDirty ? '* ' : '' - }${ - customName || name || t('styleMissingName') - } - Stylus`; // the suffix enables external utilities to process our windows e.g. pin on top - }, -}; - -//#region pre-init - -(() => { - const mqCompact = matchMedia('(max-width: 850px)'); - const toggleCompact = mq => $.rootCL.toggle('compact-layout', mq.matches); - mqCompact.on('change', toggleCompact); - toggleCompact(mqCompact); - let params = new URLSearchParams(location.search); - let id = +params.get('id'); - Object.assign(editor, /** @namespace Editor */ { - mqCompact, - styleReady: Promise.all([ - Promise.all([ - id ? API.styles.get(id) : undefined, - prefs.ready, - ]).then(loadStyle), - id && API.data.get('editorScrollInfo' + id).then(si => { - editor.scrollInfo = si || {}; - }), - new Promise(t.body), - ]), - }); - - async function loadStyle([ - style = { - id: id = null, // resetting the non-existent id - name: makeName(params), - enabled: true, - sections: [ - MozDocMapper.toSection([...params], {code: ''}), - ], - }, - ]) { - // switching the mode here to show the correct page ASAP, usually before DOMContentLoaded - const isUC = Boolean(style[UCD] || !id && prefs.get('newStyleAsUsercss')); - Object.assign(editor, /** @namespace Editor */ { - style, - isUsercss: isUC, - template: isUC && !id && chromeSync.getLZValue(chromeSync.LZ_KEY.usercssTemplate), // promise - }); - editor.updateClass(); - editor.updateTheme(prefs.get('editor.theme')); - editor.updateTitle(false); - $.rootCL.add(isUC ? 'usercss' : 'sectioned'); - sessionStore.justEditedStyleId = id || ''; - // no such style so let's clear the invalid URL parameters - if (id === null) { - params.delete('id'); - params = `${params}`; - history.replaceState({}, '', location.pathname + (params ? '?' : '') + params); - } - } - - function makeName(params) { - const prefix = tryURL(params.get('url-prefix')); - const name = params.get('name') || prefix.hostname; - const p = prefix.pathname || '/'; - return name - ? name + (p === '/' ? '' : clipString(p.replace(/\.(html?|aspx?|cgi|php)$/, ''))) - : params.get('domain') || '?'; - } -})(); - -//#endregion -//#region init header - -/* exported EditorHeader */ -function EditorHeader() { - initBeautifyButton($('#beautify')); - initNameArea(); - setupLivePrefs(); - // move the theme after built-in CSS so that its same-specificity selectors win - document.head.appendChild($('#cm-theme')); - window.on('load', () => { - prefs.subscribe('editor.keyMap', showHotkeyInTooltip, true); - window.on('showHotkeyInTooltip', showHotkeyInTooltip); - }, {once: true}); - for (const el of $$('#header details')) el.on('contextmenu', peekDetails); - - function findKeyForCommand(command, map) { - if (typeof map === 'string') map = CodeMirror.keyMap[map]; - let key = Object.keys(map).find(k => map[k] === command); - if (key) { - return key; - } - for (const ft of Array.isArray(map.fallthrough) ? map.fallthrough : [map.fallthrough]) { - key = ft && findKeyForCommand(command, ft); - if (key) { - return key; - } - } - return ''; - } - - function initNameArea() { - const nameEl = $('#name'); - const resetEl = $('#reset-name'); - const isCustomName = editor.style.updateUrl || editor.isUsercss; - editor.nameTarget = isCustomName ? 'customName' : 'name'; - nameEl.placeholder = t(editor.isUsercss ? 'usercssEditorNamePlaceholder' : 'styleMissingName'); - nameEl.title = isCustomName ? t('customNameHint') : ''; - nameEl.on('input', () => { - editor.updateName(true); - resetEl.hidden = !editor.style.customName; - }); - resetEl.hidden = !editor.style.customName; - resetEl.onclick = () => { - setInputValue(nameEl, editor.style.name); - editor.style.customName = null; // to delete it from db - resetEl.hidden = true; - }; - const enabledEl = $('#enabled'); - enabledEl.onchange = () => editor.updateEnabledness(enabledEl.checked); - } - - async function peekDetails(evt) { - evt.preventDefault(); - this.open = true; - while (this.matches(':hover, :active')) { - await new Promise(cb => setTimeout(cb, 500)); - await new Promise(cb => this.on('mouseleave', cb, {once: true})); - } - this.open = false; - } - - function showHotkeyInTooltip(_, mapName = prefs.get('editor.keyMap')) { - const extraKeys = CodeMirror.defaults.extraKeys; - for (const el of $$('[data-hotkey-tooltip]')) { - if (el._hotkeyTooltipKeyMap !== mapName) { - el._hotkeyTooltipKeyMap = mapName; - const title = el._hotkeyTooltipTitle = el._hotkeyTooltipTitle || el.title; - const cmd = el.dataset.hotkeyTooltip; - const key = cmd[0] === '=' ? cmd.slice(1) : - findKeyForCommand(cmd, mapName) || - extraKeys && findKeyForCommand(cmd, extraKeys); - const newTitle = title + (title && key ? '\n' : '') + (key || ''); - if (el.title !== newTitle) el.title = newTitle; - } - } - } -} - -//#endregion -//#region init windowed mode - -(() => { - let ownTabId; - if (chrome.windows) { - initWindowedMode(); - const pos = tryJSONparse(sessionStore.windowPos); - delete sessionStore.windowPos; - // resize the window on 'undo close' - if (pos && pos.left != null) { - chrome.windows.update(chrome.windows.WINDOW_ID_CURRENT, pos); - } - } - - getOwnTab().then(tab => { - ownTabId = tab.id; - if (sessionStore['manageStylesHistory' + ownTabId] === location.href) { - editor.cancel = () => history.back(); - } - }); - - async function initWindowedMode() { - chrome.tabs.onAttached.addListener(onTabAttached); - // Chrome 96+ bug: the type is 'app' for a window that was restored via Ctrl-Shift-T - const isSimple = ['app', 'popup'].includes((await browser.windows.getCurrent()).type); - if (isSimple) require(['/edit/embedded-popup']); - editor.isWindowed = isSimple || ( - history.length === 1 && - await prefs.ready && prefs.get('openEditInWindow') && - (await browser.windows.getAll()).length > 1 && - (await browser.tabs.query({currentWindow: true})).length === 1 - ); - } - - async function onTabAttached(tabId, info) { - if (tabId !== ownTabId) { - return; - } - if (info.newPosition !== 0) { - prefs.set('openEditInWindow', false); - return; - } - const win = await browser.windows.get(info.newWindowId, {populate: true}); - // If there's only one tab in this window, it's been dragged to new window - const openEditInWindow = win.tabs.length === 1; - // FF-only because Chrome retardedly resets the size during dragging - if (openEditInWindow && FIREFOX) { - chrome.windows.update(info.newWindowId, prefs.get('windowPosition')); - } - prefs.set('openEditInWindow', openEditInWindow); - } -})(); - -//#endregion -//#region internals - -/** @returns DirtyReporter */ -function DirtyReporter() { - const data = new Map(); - const listeners = new Set(); - const dataListeners = new Set(); - const notifyChange = wasDirty => { - const isDirty = data.size > 0; - const flipped = isDirty !== wasDirty; - if (flipped) { - listeners.forEach(cb => cb(isDirty)); - } - if (flipped || isDirty) { - dataListeners.forEach(cb => cb(isDirty)); - } - }; - /** @namespace DirtyReporter */ - return { - add(obj, value) { - const wasDirty = data.size > 0; - const saved = data.get(obj); - if (!saved) { - data.set(obj, {type: 'add', newValue: value}); - } else if (saved.type === 'remove') { - if (saved.savedValue === value) { - data.delete(obj); - } else { - saved.newValue = value; - saved.type = 'modify'; - } - } else { - return; - } - notifyChange(wasDirty); - }, - clear(id) { - if (data.size && ( - id ? data.delete(id) - : (data.clear(), true) - )) { - notifyChange(true); - } - }, - has(key) { - return data.has(key); - }, - isDirty() { - return data.size > 0; - }, - modify(obj, oldValue, newValue) { - const wasDirty = data.size > 0; - const saved = data.get(obj); - if (!saved) { - if (oldValue !== newValue) { - data.set(obj, {type: 'modify', savedValue: oldValue, newValue}); - } else { - return; - } - } else if (saved.type === 'modify') { - if (saved.savedValue === newValue) { - data.delete(obj); - } else { - saved.newValue = newValue; - } - } else if (saved.type === 'add') { - saved.newValue = newValue; - } else { - return; - } - notifyChange(wasDirty); - }, - onChange(cb, add = true) { - listeners[add ? 'add' : 'delete'](cb); - }, - onDataChange(cb, add = true) { - dataListeners[add ? 'add' : 'delete'](cb); - }, - remove(obj, value) { - const wasDirty = data.size > 0; - const saved = data.get(obj); - if (!saved) { - data.set(obj, {type: 'remove', savedValue: value}); - } else if (saved.type === 'add') { - data.delete(obj); - } else if (saved.type === 'modify') { - saved.type = 'remove'; - } else { - return; - } - notifyChange(wasDirty); - }, - }; -} - -function LivePreview() { - const ID = 'editor.livePreview'; - let errPos; - let el; - let data; - let port; - let enabled = prefs.get(ID); - - prefs.subscribe(ID, (key, value) => { - if (!value) { - if (port) { - port.disconnect(); - port = null; - } - } else if (data && data.id && (data.enabled || editor.dirty.has('enabled'))) { - createPreviewer(); - updatePreviewer(data); - } - enabled = value; - }); - - return newData => { - if (!port) { - if (!enabled - || !newData.id // not saved - || !newData.enabled && data && !data.enabled // disabled both before and now - || !editor.dirty.isDirty()) { - return; - } - createPreviewer(); - } - data = newData; - updatePreviewer(data); - }; - - function createPreviewer() { - port = chrome.runtime.connect({name: 'livePreview:' + editor.style.id}); - port.onDisconnect.addListener(() => (port = null)); - el = $('#preview-errors'); - el.onclick = showError; - } - - function showError() { - if (errPos) { - const cm = editor.getEditors()[0]; - cm.setCursor(errPos); - cm.focus(); - } - } - - async function updatePreviewer(data) { - try { - await API.styles.preview(data); - el.hidden = true; - } catch (err) { - const ucd = data[UCD]; - const pp = ucd && ucd.preprocessor; - const shift = err._varLines + 1 || 0; - errPos = pp && err.line && err.column - ? {line: err.line - shift, ch: err.column - 1} - : err.index; - if (Array.isArray(err)) { - err = err.map((e, a, b) => !(a = e.message) ? e : ((b = e.context)) ? `${a} in ${b}` : a).join('\n'); - } else { - err = err.message || `${err}`; - } - if (errPos >= 0) { - // FIXME: this would fail if editors[0].getValue() !== data.sourceCode - errPos = editor.getEditors()[0].posFromIndex(errPos); - } else if (pp === 'stylus' && (errPos = err.match(/^\w+:(\d+):(\d+)(?:\n.+)+\s+(.+)/))) { - err = errPos[3]; - errPos = {line: errPos[1] - shift, ch: errPos[2] - 1}; - } - el.title = - el.firstChild.textContent = (errPos ? `${errPos.line + 1}:${errPos.ch + 1} ` : '') + err; - el.lastChild.hidden = !(el.lastChild.href = editor.ppDemo[pp]); - el.hidden = false; - } - } -} - -//#endregion diff --git a/src/edit/beautify.js b/src/edit/beautify.js index 9522812338d..d3d2a78a68e 100644 --- a/src/edit/beautify.js +++ b/src/edit/beautify.js @@ -1,10 +1,11 @@ -/* global $ $create moveFocus */// dom.js -/* global CodeMirror */ -/* global createHotkeyInput helpPopup */// util.js -/* global editor */ -/* global prefs */ -/* global t */// localization.js -'use strict'; +import {t} from '/js/localization'; +import {$, $create, moveFocus} from '/js/dom'; +import * as prefs from '/js/prefs'; +import {require} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import {extraKeys} from './codemirror-default'; +import editor from './editor'; +import {createHotkeyInput, helpPopup} from './util'; CodeMirror.commands.beautify = cm => { // using per-section mode when code editor or applies-to block is focused @@ -13,7 +14,6 @@ CodeMirror.commands.beautify = cm => { }; prefs.subscribe('editor.beautify.hotkey', (key, value) => { - const {extraKeys} = CodeMirror.defaults; for (const [key, cmd] of Object.entries(extraKeys)) { if (cmd === 'beautify') { delete extraKeys[key]; @@ -79,7 +79,8 @@ function createBeautifyUI(scope, options) { $createOption('border: none;', 'newline_between_properties', true), $createOption('display: block;', 'newline_before_close_brace', true), $createOption('}', 'newline_between_rules'), - $createLabeledCheckbox('space_around_combinator', '', 'selector + selector', 'selector+selector'), + $createLabeledCheckbox('space_around_combinator', '', 'selector + selector', + 'selector+selector'), $createLabeledCheckbox('space_around_cmp', '', '[attribute = "1"]', '[attribute="1"]'), $createLabeledCheckbox('preserve_newlines', 'styleBeautifyPreserveNewlines'), $createLabeledCheckbox('indent_conditional', 'styleBeautifyIndentConditional'), @@ -164,8 +165,7 @@ function createBeautifyUI(scope, options) { } } -/* exported initBeautifyButton */ -function initBeautifyButton(btn, scope) { +export function initBeautifyButton(btn, scope) { btn.onclick = btn.oncontextmenu = e => { e.preventDefault(); beautify(scope || editor.getEditors(), e.type === 'click'); diff --git a/src/edit/codemirror-default.js b/src/edit/codemirror-default.js index f424b2ed296..1866907517a 100644 --- a/src/edit/codemirror-default.js +++ b/src/edit/codemirror-default.js @@ -1,10 +1,28 @@ -/* global $ */// dom.js -/* global CodeMirror */ -/* global UA deepMerge */// toolbox.js -/* global editor */ -/* global prefs */ -/* global t */// localization.js -'use strict'; +import {$} from '/js/dom'; +import CodeMirror from 'codemirror'; +import {UA, deepMerge} from '/js/toolbox'; +import editor from './editor'; +import * as prefs from '/js/prefs'; +import {t} from '/js/localization'; + +export const extraKeys = Object.assign(CodeMirror.defaults.extraKeys || {}, { + // independent of current keyMap; some are implemented only for the edit page + 'Alt-Enter': 'toggleStyle', + 'Alt-PageDown': 'nextEditor', + 'Alt-PageUp': 'prevEditor', + 'Alt-Home': 'showCurrentLineAtTop', + 'Alt-End': 'showCurrentLineAtBottom', + 'Alt-Down': 'minus1', + 'Alt-Up': 'plus1', + 'Shift-Alt-Down': 'minus10', + 'Shift-Alt-Up': 'plus10', + 'Shift-Ctrl-Alt-Down': 'minus100', + 'Shift-Ctrl-Alt-Up': 'plus100', + // Adding dummy Wheel shortcuts to show it in keymap (i) popup + 'Ctrl-Alt-WheelDown': 'minus100', + 'Ctrl-Alt-WheelUp': 'plus100', + 'Ctrl-Pause': 'toggleEditorFocus', +}); prefs.ready.then(() => { // CodeMirror miserably fails on keyMap='' so let's ensure it's not @@ -29,24 +47,7 @@ prefs.ready.then(() => { styleActiveLine: {nonEmpty: true}, theme: prefs.get('editor.theme'), keyMap: prefs.get('editor.keyMap'), - extraKeys: Object.assign(CodeMirror.defaults.extraKeys || {}, { - // independent of current keyMap; some are implemented only for the edit page - 'Alt-Enter': 'toggleStyle', - 'Alt-PageDown': 'nextEditor', - 'Alt-PageUp': 'prevEditor', - 'Alt-Home': 'showCurrentLineAtTop', - 'Alt-End': 'showCurrentLineAtBottom', - 'Alt-Down': 'minus1', - 'Alt-Up': 'plus1', - 'Shift-Alt-Down': 'minus10', - 'Shift-Alt-Up': 'plus10', - 'Shift-Ctrl-Alt-Down': 'minus100', - 'Shift-Ctrl-Alt-Up': 'plus100', - // Adding dummy Wheel shortcuts to show it in keymap (i) popup - 'Ctrl-Alt-WheelDown': 'minus100', - 'Ctrl-Alt-WheelUp': 'plus100', - 'Ctrl-Pause': 'toggleEditorFocus', - }), + extraKeys, maxHighlightLength: 100e3, undoDepth: 1000, }; @@ -57,7 +58,7 @@ prefs.ready.then(() => { // Adding hotkeys to some keymaps except 'basic' which is primitive by design { const KM = CodeMirror.keyMap; - const extras = Object.values(CodeMirror.defaults.extraKeys); + const extras = Object.values(extraKeys); if (!extras.includes('jumpToLine')) { KM.sublime['Ctrl-G'] = 'jumpToLine'; KM.emacsy['Ctrl-G'] = 'jumpToLine'; diff --git a/src/edit/codemirror-factory.js b/src/edit/codemirror-factory.js index 43a527d40dc..33a8cb1a751 100644 --- a/src/edit/codemirror-factory.js +++ b/src/edit/codemirror-factory.js @@ -1,9 +1,8 @@ -/* global CHROME */// toolbox.js -/* global CodeMirror */ -/* global editor */ -/* global prefs */ -/* global rerouteHotkeys */// util.js -'use strict'; +import {rerouteHotkeys} from '/edit/util'; +import {CHROME} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import editor from './editor'; +import * as prefs from '/js/prefs'; /* All cm instances created by this module are collected so we can broadcast prefs @@ -11,70 +10,69 @@ when the instance is not used anymore. */ -prefs.ready.then(() => { - //#region Factory - - const cms = new Set(); - let lazyOpt; - - const cmDefaults = CodeMirror.defaults; - const cmFactory = window.cmFactory = { - - create(place, options) { - const cm = CodeMirror(place, options); - cm.display.lineDiv.on('mousewheel', plusMinusOnWheel.bind(cm), true); - // TODO: remove when CM stops adding it unconditionally or minimum_chrome_version >= 106 - if (CHROME !== 105) cm.display.wrapper.style.removeProperty('clip-path'); - cm.lastActive = 0; - cms.add(cm); - return cm; - }, - - destroy(cm) { - cms.delete(cm); - }, - - globalSetOption(key, value) { - cmDefaults[key] = value; - if (cms.size > 4 && lazyOpt.names.includes(key)) { - lazyOpt.set(key, value); - } else { - cms.forEach(cm => cm.setOption(key, value)); - } - }, - }; - - // focus and blur - - const onCmFocus = cm => { - rerouteHotkeys.toggle(false); - cm.display.wrapper.classList.add('CodeMirror-active'); - cm.lastActive = Date.now(); - }; - const onCmBlur = cm => { - setTimeout(() => { - /* Delaying to next tick to avoid double-processing of the currently processed keyboard event - * when it bubbles up from CodeMirror to `document` where the rerouter listens */ - rerouteHotkeys.toggle(true); - const {wrapper} = cm.display; - wrapper.classList.toggle('CodeMirror-active', wrapper.contains(document.activeElement)); - }); - }; - CodeMirror.defineInitHook(cm => { - cm.on('focus', onCmFocus); - cm.on('blur', onCmBlur); +//#region Factory + +const cms = new Set(); +const cmDefaults = CodeMirror.defaults; +const cmFactory = { + + create(place, options) { + const cm = CodeMirror(place, options); + cm.display.lineDiv.on('mousewheel', plusMinusOnWheel.bind(cm), true); + // TODO: remove when CM stops adding it unconditionally or minimum_chrome_version >= 106 + if (CHROME !== 105) cm.display.wrapper.style.removeProperty('clip-path'); + cm.lastActive = 0; + cms.add(cm); + return cm; + }, + + destroy(cm) { + cms.delete(cm); + }, + + globalSetOption(key, value) { + cmDefaults[key] = value; + // eslint-disable-next-line no-use-before-define + if (cms.size > 4 && lazyOpt.names.includes(key)) { + lazyOpt.set(key, value); // eslint-disable-line no-use-before-define + } else { + cms.forEach(cm => cm.setOption(key, value)); + } + }, +}; + +// focus and blur + +const onCmFocus = cm => { + rerouteHotkeys.toggle(false); + cm.display.wrapper.classList.add('CodeMirror-active'); + cm.lastActive = Date.now(); +}; +const onCmBlur = cm => { + setTimeout(() => { + /* Delaying to next tick to avoid double-processing of the currently processed keyboard event + * when it bubbles up from CodeMirror to `document` where the rerouter listens */ + rerouteHotkeys.toggle(true); + const {wrapper} = cm.display; + wrapper.classList.toggle('CodeMirror-active', wrapper.contains(document.activeElement)); }); +}; +CodeMirror.defineInitHook(cm => { + cm.on('focus', onCmFocus); + cm.on('blur', onCmBlur); +}); - // propagated preferences +// propagated preferences - const prefToCmOpt = k => - k.startsWith('editor.') && - k.slice('editor.'.length); - const prefKeys = prefs.knownKeys.filter(k => - k !== 'editor.colorpicker' && // handled in colorpicker-helper.js - k !== 'editor.arrowKeysTraverse' && // handled in sections-editor.js - prefToCmOpt(k) in CodeMirror.defaults); - const {insertTab, insertSoftTab} = CodeMirror.commands; +const prefToCmOpt = k => + k.startsWith('editor.') && + k.slice('editor.'.length); +const prefKeys = prefs.knownKeys.filter(k => + k !== 'editor.colorpicker' && // handled in colorpicker-helper.js + k !== 'editor.arrowKeysTraverse' && // handled in sections-editor.js + prefToCmOpt(k) in CodeMirror.defaults); +const {insertTab, insertSoftTab} = CodeMirror.commands; +prefs.ready.then(() => { for (const key of prefKeys) { cmDefaults[prefToCmOpt(key)] = prefs.get(key); } @@ -102,254 +100,256 @@ prefs.ready.then(() => { CodeMirror.defineOption(prefToCmOpt(key), prefs.get(key), fn); prefKeys.push(key); } +}); - prefs.subscribe(prefKeys, (key, val) => { - if (key === 'editor.theme') editor.updateTheme(val); - cmFactory.globalSetOption(prefToCmOpt(key), val); - }); +prefs.subscribe(prefKeys, (key, val) => { + if (key === 'editor.theme') editor.updateTheme(val); + cmFactory.globalSetOption(prefToCmOpt(key), val); +}); - // lazy propagation - - lazyOpt = { - names: ['theme', 'lineWrapping'], - set(key, value) { - const {observer, queue} = lazyOpt; - for (const cm of cms) { - let opts = queue.get(cm); - if (!opts) queue.set(cm, opts = {}); - opts[key] = value; - observer.observe(cm.display.wrapper); - } - }, - setNow({cm, data}) { - cm.operation(() => data.forEach(kv => cm.setOption(...kv))); - }, - onView(entries) { - const {queue, observer} = lazyOpt; - const delayed = []; - for (const e of entries) { - const r = e.intersectionRatio && e.intersectionRect; - if (!r) continue; - const cm = e.target.CodeMirror; - const data = Object.entries(queue.get(cm) || {}); - queue.delete(cm); - observer.unobserve(e.target); - if (!data.every(([key, val]) => cm.getOption(key) === val)) { - if (r.bottom > 0 && r.top < window.innerHeight) { - lazyOpt.setNow({cm, data}); - } else { - delayed.push({cm, data}); - } +// lazy propagation + +const lazyOpt = { + names: ['theme', 'lineWrapping'], + set(key, value) { + const {observer, queue} = lazyOpt; + for (const cm of cms) { + let opts = queue.get(cm); + if (!opts) queue.set(cm, opts = {}); + opts[key] = value; + observer.observe(cm.display.wrapper); + } + }, + setNow({cm, data}) { + cm.operation(() => data.forEach(kv => cm.setOption(...kv))); + }, + onView(entries) { + const {queue, observer} = lazyOpt; + const delayed = []; + for (const e of entries) { + const r = e.intersectionRatio && e.intersectionRect; + if (!r) continue; + const cm = e.target.CodeMirror; + const data = Object.entries(queue.get(cm) || {}); + queue.delete(cm); + observer.unobserve(e.target); + if (!data.every(([key, val]) => cm.getOption(key) === val)) { + if (r.bottom > 0 && r.top < window.innerHeight) { + lazyOpt.setNow({cm, data}); + } else { + delayed.push({cm, data}); } } - if (delayed.length) { - setTimeout(() => delayed.forEach(lazyOpt.setNow)); - } - }, - get observer() { - if (!lazyOpt._observer) { - // must exceed refreshOnView's 100% - lazyOpt._observer = new IntersectionObserver(lazyOpt.onView, {rootMargin: '150%'}); - lazyOpt.queue = new WeakMap(); - } - return lazyOpt._observer; - }, - }; - - //#endregion - //#region Commands - - Object.assign(CodeMirror.commands, { - commentSelection(cm) { - cm.blockComment(cm.getCursor('from'), cm.getCursor('to'), {fullLines: false}); - }, - minus1: plusMinus.bind(null, -1), - minus10: plusMinus.bind(null, -10), - minus100: plusMinus.bind(null, -100), - plus1: plusMinus.bind(null, 1), - plus10: plusMinus.bind(null, 10), - plus100: plusMinus.bind(null, 100), - toggleEditorFocus(cm) { - if (!cm) return; - if (cm.hasFocus()) { - setTimeout(() => cm.display.input.blur()); - } else { - cm.focus(); - } - }, - }); - for (const cmd of [ - 'nextEditor', - 'prevEditor', - 'save', - 'toggleStyle', - ]) { - CodeMirror.commands[cmd] = (...args) => editor[cmd](...args); - } - - function plusMinus(delta, cm, pos = cm.getCursor()) { - const {line, ch} = pos; - const {text} = cm.getLineHandle(line); - let m = /[-+\d.%a-z]/iy; - let i = m.lastIndex = ch; - if (!m.test(text)) i += !i || (m.lastIndex = i - 1, m.test(text)) ? -1 : 1; - // find where the number+unit starts - do m.lastIndex = i; - while (i > ch - 20 && (m.test(text) ? --i >= 0 : (++i, false))); - // get the number - m = /[-+]?(\d*\.)?(\d+)/y; - m.lastIndex = i; - m = m.exec(text); - if (!m) return; - if (m[0].includes('.')) delta /= 10; - cm.replaceRange((+m[0] + delta).toFixed(m[1] ? m[2].length : 0), - {line, ch: i}, - {line, ch: i + m[0].length}, - '*incdec' + line + ':' + i); - } - - function plusMinusOnWheel(e) { - if (e.altKey) { - e.preventDefault(); - plusMinus((e.ctrlKey ? 100 : e.shiftKey ? 10 : 1) * (e.wheelDeltaY > 0 ? 1 : -1), this, - this.coordsChar({left: e.clientX, top: e.clientY}, 'window')); } - } - - //#endregion - //#region CM option handlers - - function updateMatchHighlightCount(cm, state) { - cm.display.wrapper.dataset.matchHighlightCount = state.matchesonscroll.matches.length; - } - - function configureMouseFn(cm, repeat) { - return repeat === 'double' ? - {unit: selectTokenOnDoubleclick} : - {}; - } - - function selectTokenOnDoubleclick(cm, pos) { - let {ch} = pos; - const {line, sticky} = pos; - const {text, styles} = cm.getLineHandle(line); - - const execAt = (rx, i) => (rx.lastIndex = i) && null || rx.exec(text); - const at = (rx, i) => (rx.lastIndex = i) && null || rx.test(text); - const atWord = ch => at(/\w/y, ch); - const atSpace = ch => at(/\s/y, ch); - - const atTokenEnd = styles.indexOf(ch, 1); - ch += atTokenEnd < 0 ? 0 : sticky === 'before' && atWord(ch - 1) ? 0 : atSpace(ch + 1) ? 0 : 1; - ch = Math.min(text.length, ch); - const type = cm.getTokenTypeAt({line, ch: ch + (sticky === 'after' ? 1 : 0)}); - if (atTokenEnd > 0) ch--; - - const isCss = type && !/^(comment|string)/.test(type); - const isNumber = type === 'number'; - const isSpace = atSpace(ch); - let wordChars = - isNumber ? /[-+\w.%]/y : - isCss ? /[-\w@]/y : - isSpace ? /\s/y : - atWord(ch) ? /\w/y : /[^\w\s]/y; - - let a = ch; - while (a && at(wordChars, a)) a--; - a += !a && at(wordChars, a) || isCss && at(/[.!#@]/y, a) ? 0 : at(wordChars, a + 1); - - let b, found; - - if (isNumber) { - b = a + execAt(/[+-]?[\d.]+(e\d+)?|$/yi, a)[0].length; - found = b >= ch; - if (!found) { - a = b; - ch = a; - } + if (delayed.length) { + setTimeout(() => delayed.forEach(lazyOpt.setNow)); } - + }, + get observer() { + if (!lazyOpt._observer) { + // must exceed refreshOnView's 100% + lazyOpt._observer = new IntersectionObserver(lazyOpt.onView, {rootMargin: '150%'}); + lazyOpt.queue = new WeakMap(); + } + return lazyOpt._observer; + }, +}; + +//#endregion +//#region Commands + +Object.assign(CodeMirror.commands, { + commentSelection(cm) { + cm.blockComment(cm.getCursor('from'), cm.getCursor('to'), {fullLines: false}); + }, + minus1: plusMinus.bind(null, -1), + minus10: plusMinus.bind(null, -10), + minus100: plusMinus.bind(null, -100), + plus1: plusMinus.bind(null, 1), + plus10: plusMinus.bind(null, 10), + plus100: plusMinus.bind(null, 100), + toggleEditorFocus(cm) { + if (!cm) return; + if (cm.hasFocus()) { + setTimeout(() => cm.display.input.blur()); + } else { + cm.focus(); + } + }, +}); +for (const cmd of [ + 'nextEditor', + 'prevEditor', + 'save', + 'toggleStyle', +]) { + CodeMirror.commands[cmd] = (...args) => editor[cmd](...args); +} + +function plusMinus(delta, cm, pos = cm.getCursor()) { + const {line, ch} = pos; + const {text} = cm.getLineHandle(line); + let m = /[-+\d.%a-z]/iy; + let i = m.lastIndex = ch; + if (!m.test(text)) i += !i || (m.lastIndex = i - 1, m.test(text)) ? -1 : 1; + // find where the number+unit starts + do m.lastIndex = i; + while (i > ch - 20 && (m.test(text) ? --i >= 0 : (++i, false))); + // get the number + m = /[-+]?(\d*\.)?(\d+)/y; + m.lastIndex = i; + m = m.exec(text); + if (!m) return; + if (m[0].includes('.')) delta /= 10; + cm.replaceRange((+m[0] + delta).toFixed(m[1] ? m[2].length : 0), + {line, ch: i}, + {line, ch: i + m[0].length}, + '*incdec' + line + ':' + i); +} + +function plusMinusOnWheel(e) { + if (e.altKey) { + e.preventDefault(); + plusMinus((e.ctrlKey ? 100 : e.shiftKey ? 10 : 1) * (e.wheelDeltaY > 0 ? 1 : -1), this, + this.coordsChar({left: e.clientX, top: e.clientY}, 'window')); + } +} + +//#endregion +//#region CM option handlers + +function updateMatchHighlightCount(cm, state) { + cm.display.wrapper.dataset.matchHighlightCount = state.matchesonscroll.matches.length; +} + +function configureMouseFn(cm, repeat) { + return repeat === 'double' ? + {unit: selectTokenOnDoubleclick} : + {}; +} + +function selectTokenOnDoubleclick(cm, pos) { + let {ch} = pos; + const {line, sticky} = pos; + const {text, styles} = cm.getLineHandle(line); + + const execAt = (rx, i) => (rx.lastIndex = i) && null || rx.exec(text); + const at = (rx, i) => (rx.lastIndex = i) && null || rx.test(text); + const atWord = ch => at(/\w/y, ch); + const atSpace = ch => at(/\s/y, ch); + + const atTokenEnd = styles.indexOf(ch, 1); + ch += atTokenEnd < 0 ? 0 : sticky === 'before' && atWord(ch - 1) ? 0 : atSpace(ch + 1) ? 0 : 1; + ch = Math.min(text.length, ch); + const type = cm.getTokenTypeAt({line, ch: ch + (sticky === 'after' ? 1 : 0)}); + if (atTokenEnd > 0) ch--; + + const isCss = type && !/^(comment|string)/.test(type); + const isNumber = type === 'number'; + const isSpace = atSpace(ch); + let wordChars = + isNumber ? /[-+\w.%]/y : + isCss ? /[-\w@]/y : + isSpace ? /\s/y : + atWord(ch) ? /\w/y : /[^\w\s]/y; + + let a = ch; + while (a && at(wordChars, a)) a--; + a += !a && at(wordChars, a) || isCss && at(/[.!#@]/y, a) ? 0 : at(wordChars, a + 1); + + let b, found; + + if (isNumber) { + b = a + execAt(/[+-]?[\d.]+(e\d+)?|$/yi, a)[0].length; + found = b >= ch; if (!found) { - wordChars = isCss ? /[-\w]*/y : new RegExp(wordChars.source + '*', 'uy'); - b = ch + execAt(wordChars, ch)[0].length; + a = b; + ch = a; } - - return { - from: {line, ch: a}, - to: {line, ch: b}, - }; } - //#endregion - //#region Bookmarks - - const BM_CLS = 'gutter-bookmark'; - const BM_BRAND = 'sublimeBookmark'; - const BM_CLICKER = 'CodeMirror-linenumbers'; - const BM_DATA = Symbol('data'); - // TODO: revisit when https://github.com/codemirror/CodeMirror/issues/6716 is fixed - const tmProto = CodeMirror.TextMarker.prototype; - const tmProtoOvr = {}; - for (const k of ['clear', 'attachLine', 'detachLine']) { - tmProtoOvr[k] = function (line) { - const {cm} = this.doc; - const withOp = !cm.curOp; - if (withOp) cm.startOperation(); - tmProto[k].apply(this, arguments); - cm.curOp.ownsGroup.delayedCallbacks.push(toggleMark.bind(this, this.lines[0], line)); - if (withOp) cm.endOperation(); - }; - } - for (const name of ['prevBookmark', 'nextBookmark']) { - const cmdFn = CodeMirror.commands[name]; - CodeMirror.commands[name] = cm => { - cm.setSelection = cm.jumpToPos; - cmdFn(cm); - delete cm.setSelection; - }; + if (!found) { + wordChars = isCss ? /[-\w]*/y : new RegExp(wordChars.source + '*', 'uy'); + b = ch + execAt(wordChars, ch)[0].length; } - CodeMirror.defineInitHook(cm => { - cm.on('gutterClick', onGutterClick); - cm.on('gutterContextMenu', onGutterContextMenu); - cm.on('markerAdded', onMarkAdded); - }); - // TODO: reimplement bookmarking so next/prev order is decided solely by the line numbers - function onGutterClick(cm, line, name, e) { - switch (name === BM_CLICKER && e.button) { - case 0: { - // main button: toggle - const [mark] = cm.findMarks({line, ch: 0}, {line, ch: 1e9}, m => m[BM_BRAND]); - cm.setCursor(mark ? mark.find(-1) : {line, ch: 0}); - cm.execCommand('toggleBookmark'); - break; - } - case 1: - // middle button: select all marks - cm.execCommand('selectBookmarks'); - break; + + return { + from: {line, ch: a}, + to: {line, ch: b}, + }; +} + +//#endregion +//#region Bookmarks + +const BM_CLS = 'gutter-bookmark'; +const BM_BRAND = 'sublimeBookmark'; +const BM_CLICKER = 'CodeMirror-linenumbers'; +const BM_DATA = Symbol('data'); +// TODO: revisit when https://github.com/codemirror/CodeMirror/issues/6716 is fixed +const tmProto = CodeMirror.TextMarker.prototype; +const tmProtoOvr = {}; +for (const k of ['clear', 'attachLine', 'detachLine']) { + tmProtoOvr[k] = function (line) { + const {cm} = this.doc; + const withOp = !cm.curOp; + if (withOp) cm.startOperation(); + tmProto[k].apply(this, arguments); + cm.curOp.ownsGroup.delayedCallbacks.push(toggleMark.bind(this, this.lines[0], line)); + if (withOp) cm.endOperation(); + }; +} +for (const name of ['prevBookmark', 'nextBookmark']) { + const cmdFn = CodeMirror.commands[name]; + CodeMirror.commands[name] = cm => { + cm.setSelection = cm.jumpToPos; + cmdFn(cm); + delete cm.setSelection; + }; +} +CodeMirror.defineInitHook(cm => { + cm.on('gutterClick', onGutterClick); + cm.on('gutterContextMenu', onGutterContextMenu); + cm.on('markerAdded', onMarkAdded); +}); +// TODO: reimplement bookmarking so next/prev order is decided solely by the line numbers +function onGutterClick(cm, line, name, e) { + switch (name === BM_CLICKER && e.button) { + case 0: { + // main button: toggle + const [mark] = cm.findMarks({line, ch: 0}, {line, ch: 1e9}, m => m[BM_BRAND]); + cm.setCursor(mark ? mark.find(-1) : {line, ch: 0}); + cm.execCommand('toggleBookmark'); + break; } + case 1: + // middle button: select all marks + cm.execCommand('selectBookmarks'); + break; } - function onGutterContextMenu(cm, line, name, e) { - if (name === BM_CLICKER) { - cm.execCommand(e.ctrlKey ? 'prevBookmark' : 'nextBookmark'); - e.preventDefault(); - } +} +function onGutterContextMenu(cm, line, name, e) { + if (name === BM_CLICKER) { + cm.execCommand(e.ctrlKey ? 'prevBookmark' : 'nextBookmark'); + e.preventDefault(); } - function onMarkAdded(cm, mark) { - if (mark[BM_BRAND]) { - // CM bug workaround to keep the mark at line start when the above line is removed - mark.inclusiveRight = true; - Object.assign(mark, tmProtoOvr); - toggleMark.call(mark, true, mark[BM_DATA] = mark.lines[0]); - } +} +function onMarkAdded(cm, mark) { + if (mark[BM_BRAND]) { + // CM bug workaround to keep the mark at line start when the above line is removed + mark.inclusiveRight = true; + Object.assign(mark, tmProtoOvr); + toggleMark.call(mark, true, mark[BM_DATA] = mark.lines[0]); } - function toggleMark(state, line = this[BM_DATA]) { - this.doc[state ? 'addLineClass' : 'removeLineClass'](line, 'gutter', BM_CLS); - if (state) { - const bms = this.doc.cm.state.sublimeBookmarks; - if (!bms.includes(this)) bms.push(this); - } +} +function toggleMark(state, line = this[BM_DATA]) { + this.doc[state ? 'addLineClass' : 'removeLineClass'](line, 'gutter', BM_CLS); + if (state) { + const bms = this.doc.cm.state.sublimeBookmarks; + if (!bms.includes(this)) bms.push(this); } +} - //#endregion -}); +//#endregion + +export default cmFactory; diff --git a/src/edit/codemirror-themes.js b/src/edit/codemirror-themes.js index eaf1d9cfe32..de40f76ca41 100644 --- a/src/edit/codemirror-themes.js +++ b/src/edit/codemirror-themes.js @@ -1,71 +1,70 @@ /* Do not edit. This file is auto-generated by build-vendor.js */ -/* eslint-disable max-len, quotes */ -'use strict'; -window.CODEMIRROR_THEMES = { - '3024-day': "/*\n\n Name: 3024 day\n Author: Jan T. Sott (http://github.com/idleberg)\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-3024-day.CodeMirror { background: #f7f7f7; color: #3a3432; }\n.cm-s-3024-day div.CodeMirror-selected { background: #d6d5d4; }\n\n.cm-s-3024-day .CodeMirror-line::selection, .cm-s-3024-day .CodeMirror-line > span::selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d6d5d4; }\n.cm-s-3024-day .CodeMirror-line::-moz-selection, .cm-s-3024-day .CodeMirror-line > span::-moz-selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d9d9d9; }\n\n.cm-s-3024-day .CodeMirror-gutters { background: #f7f7f7; border-right: 0px; }\n.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; }\n.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; }\n.cm-s-3024-day .CodeMirror-linenumber { color: #807d7c; }\n\n.cm-s-3024-day .CodeMirror-cursor { border-left: 1px solid #5c5855; }\n\n.cm-s-3024-day span.cm-comment { color: #cdab53; }\n.cm-s-3024-day span.cm-atom { color: #a16a94; }\n.cm-s-3024-day span.cm-number { color: #a16a94; }\n\n.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute { color: #01a252; }\n.cm-s-3024-day span.cm-keyword { color: #db2d20; }\n.cm-s-3024-day span.cm-string { color: #fded02; }\n\n.cm-s-3024-day span.cm-variable { color: #01a252; }\n.cm-s-3024-day span.cm-variable-2 { color: #01a0e4; }\n.cm-s-3024-day span.cm-def { color: #e8bbd0; }\n.cm-s-3024-day span.cm-bracket { color: #3a3432; }\n.cm-s-3024-day span.cm-tag { color: #db2d20; }\n.cm-s-3024-day span.cm-link { color: #a16a94; }\n.cm-s-3024-day span.cm-error { background: #db2d20; color: #5c5855; }\n\n.cm-s-3024-day .CodeMirror-activeline-background { background: #e8f2ff; }\n.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important; }\n", - '3024-night': "/*\n\n Name: 3024 night\n Author: Jan T. Sott (http://github.com/idleberg)\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-3024-night.CodeMirror { background: #090300; color: #d6d5d4; }\n.cm-s-3024-night div.CodeMirror-selected { background: #3a3432; }\n.cm-s-3024-night .CodeMirror-line::selection, .cm-s-3024-night .CodeMirror-line > span::selection, .cm-s-3024-night .CodeMirror-line > span > span::selection { background: rgba(58, 52, 50, .99); }\n.cm-s-3024-night .CodeMirror-line::-moz-selection, .cm-s-3024-night .CodeMirror-line > span::-moz-selection, .cm-s-3024-night .CodeMirror-line > span > span::-moz-selection { background: rgba(58, 52, 50, .99); }\n.cm-s-3024-night .CodeMirror-gutters { background: #090300; border-right: 0px; }\n.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; }\n.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; }\n.cm-s-3024-night .CodeMirror-linenumber { color: #5c5855; }\n\n.cm-s-3024-night .CodeMirror-cursor { border-left: 1px solid #807d7c; }\n\n.cm-s-3024-night span.cm-comment { color: #cdab53; }\n.cm-s-3024-night span.cm-atom { color: #a16a94; }\n.cm-s-3024-night span.cm-number { color: #a16a94; }\n\n.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute { color: #01a252; }\n.cm-s-3024-night span.cm-keyword { color: #db2d20; }\n.cm-s-3024-night span.cm-string { color: #fded02; }\n\n.cm-s-3024-night span.cm-variable { color: #01a252; }\n.cm-s-3024-night span.cm-variable-2 { color: #01a0e4; }\n.cm-s-3024-night span.cm-def { color: #e8bbd0; }\n.cm-s-3024-night span.cm-bracket { color: #d6d5d4; }\n.cm-s-3024-night span.cm-tag { color: #db2d20; }\n.cm-s-3024-night span.cm-link { color: #a16a94; }\n.cm-s-3024-night span.cm-error { background: #db2d20; color: #807d7c; }\n\n.cm-s-3024-night .CodeMirror-activeline-background { background: #2F2F2F; }\n.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'abbott': "/*\n * abbott.css\n * A warm, dark theme for prose and code, with pastels and pretty greens.\n *\n * Ported from abbott.vim (https://github.com/bcat/abbott.vim) version 2.1.\n * Original design and CodeMirror port by Jonathan Rascher.\n *\n * This theme shares the following color palette with the Vim color scheme.\n *\n * Brown shades:\n * bistre: #231c14\n * chocolate: #3c3022\n * cocoa: #745d42\n * vanilla_cream: #fef3b4\n *\n * Red shades:\n * crimson: #d80450\n * cinnabar: #f63f05\n *\n * Green shades:\n * dark_olive: #273900\n * forest_green: #24a507\n * chartreuse: #a0ea00\n * pastel_chartreuse: #d8ff84\n *\n * Yellow shades:\n * marigold: #fbb32f\n * lemon_meringue: #fbec5d\n *\n * Blue shades:\n * cornflower_blue: #3f91f1\n * periwinkle_blue: #8ccdf0\n *\n * Magenta shades:\n * french_pink: #ec6c99\n * lavender: #e6a2f3\n *\n * Cyan shades:\n * zomp: #39a78d\n * seafoam_green: #00ff7f\n */\n\n/* Style the UI: */\n\n/* Equivalent to Vim's Normal group. */\n.cm-s-abbott.CodeMirror {\n background: #231c14 /* bistre */;\n color: #d8ff84 /* pastel_chartreuse */;\n}\n\n/* Roughly equivalent to Vim's LineNr group. */\n.cm-s-abbott .CodeMirror-gutters {\n background: #231c14 /* bistre */;\n border: none;\n}\n.cm-s-abbott .CodeMirror-linenumber { color: #fbec5d /* lemon_meringue */; }\n\n.cm-s-abbott .CodeMirror-guttermarker { color: #f63f05 /* cinnabar */; }\n\n/* Roughly equivalent to Vim's FoldColumn group. */\n.cm-s-abbott .CodeMirror-guttermarker-subtle { color: #fbb32f /* marigold */; }\n\n/*\n * Roughly equivalent to Vim's CursorColumn group. (We use a brighter color\n * since Vim's cursorcolumn option highlights a whole column, whereas\n * CodeMirror's rule just highlights a thin line.)\n */\n.cm-s-abbott .CodeMirror-ruler { border-color: #745d42 /* cocoa */; }\n\n/* Equivalent to Vim's Cursor group in insert mode. */\n.cm-s-abbott .CodeMirror-cursor { border-color: #a0ea00 /* chartreuse */; }\n\n/* Equivalent to Vim's Cursor group in normal mode. */\n.cm-s-abbott.cm-fat-cursor .CodeMirror-cursor,\n.cm-s-abbott .cm-animate-fat-cursor {\n /*\n * CodeMirror doesn't allow changing the foreground color of the character\n * under the cursor, so we can't use a reverse video effect for the cursor.\n * Instead, make it semitransparent.\n */\n background: rgba(160, 234, 0, 0.5) /* chartreuse */;\n}\n.cm-s-abbott.cm-fat-cursor .CodeMirror-cursors {\n /*\n * Boost the z-index so the fat cursor shows up on top of text and\n * matchingbracket/matchingtag highlights.\n */\n z-index: 3;\n}\n\n/* Equivalent to Vim's Cursor group in replace mode. */\n.cm-s-abbott .CodeMirror-overwrite .CodeMirror-cursor {\n border-bottom: 1px solid #a0ea00 /* chartreuse */;\n border-left: none;\n width: auto;\n}\n\n/* Roughly equivalent to Vim's CursorIM group. */\n.cm-s-abbott .CodeMirror-secondarycursor {\n border-color: #00ff7f /* seafoam_green */;\n}\n\n/* Roughly equivalent to Vim's Visual group. */\n.cm-s-abbott .CodeMirror-selected,\n.cm-s-abbott.CodeMirror-focused .CodeMirror-selected {\n background: #273900 /* dark_olive */;\n}\n.cm-s-abbott .CodeMirror-line::selection,\n.cm-s-abbott .CodeMirror-line > span::selection,\n.cm-s-abbott .CodeMirror-line > span > span::selection {\n background: #273900 /* dark_olive */;\n}\n.cm-s-abbott .CodeMirror-line::-moz-selection,\n.cm-s-abbott .CodeMirror-line > span::-moz-selection,\n.cm-s-abbott .CodeMirror-line > span > span::-moz-selection {\n background: #273900 /* dark_olive */;\n}\n\n/* Roughly equivalent to Vim's SpecialKey group. */\n.cm-s-abbott .cm-tab { color: #00ff7f /* seafoam_green */; }\n\n/* Equivalent to Vim's Search group. */\n.cm-s-abbott .cm-searching {\n background: #fef3b4 /* vanilla_cream */ !important;\n color: #231c14 /* bistre */ !important;\n}\n\n/* Style syntax highlighting modes: */\n\n/* Equivalent to Vim's Comment group. */\n.cm-s-abbott span.cm-comment {\n color: #fbb32f /* marigold */;\n font-style: italic;\n}\n\n/* Equivalent to Vim's String group. */\n.cm-s-abbott span.cm-string,\n.cm-s-abbott span.cm-string-2 {\n color: #e6a2f3 /* lavender */;\n}\n\n/* Equivalent to Vim's Constant group. */\n.cm-s-abbott span.cm-number,\n.cm-s-abbott span.cm-string.cm-url { color: #f63f05 /* cinnabar */; }\n\n/* Roughly equivalent to Vim's SpecialKey group. */\n.cm-s-abbott span.cm-invalidchar { color: #00ff7f /* seafoam_green */; }\n\n/* Equivalent to Vim's Special group. */\n.cm-s-abbott span.cm-atom { color: #fef3b4 /* vanilla_cream */; }\n\n/* Equivalent to Vim's Delimiter group. */\n.cm-s-abbott span.cm-bracket,\n.cm-s-abbott span.cm-punctuation {\n color: #fef3b4 /* vanilla_cream */;\n}\n\n/* Equivalent Vim's Operator group. */\n.cm-s-abbott span.cm-operator { font-weight: bold; }\n\n/* Roughly equivalent to Vim's Identifier group. */\n.cm-s-abbott span.cm-def,\n.cm-s-abbott span.cm-variable,\n.cm-s-abbott span.cm-variable-2,\n.cm-s-abbott span.cm-variable-3 {\n color: #8ccdf0 /* periwinkle_blue */;\n}\n\n/* Roughly equivalent to Vim's Function group. */\n.cm-s-abbott span.cm-builtin,\n.cm-s-abbott span.cm-property,\n.cm-s-abbott span.cm-qualifier {\n color: #3f91f1 /* cornflower_blue */;\n}\n\n/* Equivalent to Vim's Type group. */\n.cm-s-abbott span.cm-type { color: #24a507 /* forest_green */; }\n\n/* Equivalent to Vim's Keyword group. */\n.cm-s-abbott span.cm-keyword {\n color: #d80450 /* crimson */;\n font-weight: bold;\n}\n\n/* Equivalent to Vim's PreProc group. */\n.cm-s-abbott span.cm-meta { color: #ec6c99 /* french_pink */; }\n\n/* Equivalent to Vim's htmlTagName group (linked to Statement). */\n.cm-s-abbott span.cm-tag {\n color: #d80450 /* crimson */;\n font-weight: bold;\n}\n\n/* Equivalent to Vim's htmlArg group (linked to Type). */\n.cm-s-abbott span.cm-attribute { color: #24a507 /* forest_green */; }\n\n/* Equivalent to Vim's htmlH1, markdownH1, etc. groups (linked to Title). */\n.cm-s-abbott span.cm-header {\n color: #d80450 /* crimson */;\n font-weight: bold;\n}\n\n/* Equivalent to Vim's markdownRule group (linked to PreProc). */\n.cm-s-abbott span.cm-hr { color: #ec6c99 /* french_pink */; }\n\n/* Roughly equivalent to Vim's Underlined group. */\n.cm-s-abbott span.cm-link { color: #e6a2f3 /* lavender */; }\n\n/* Equivalent to Vim's diffRemoved group. */\n.cm-s-abbott span.cm-negative {\n background: #d80450 /* crimson */;\n color: #231c14 /* bistre */;\n}\n\n/* Equivalent to Vim's diffAdded group. */\n.cm-s-abbott span.cm-positive {\n background: #a0ea00 /* chartreuse */;\n color: #231c14 /* bistre */;\n font-weight: bold;\n}\n\n/* Equivalent to Vim's Error group. */\n.cm-s-abbott span.cm-error {\n background: #d80450 /* crimson */;\n color: #231c14 /* bistre */;\n}\n\n/* Style addons: */\n\n/* Equivalent to Vim's MatchParen group. */\n.cm-s-abbott span.CodeMirror-matchingbracket {\n background: #745d42 /* cocoa */ !important;\n color: #231c14 /* bistre */ !important;\n font-weight: bold;\n}\n\n/*\n * Roughly equivalent to Vim's Error group. (Vim doesn't seem to have a direct\n * equivalent in its own matchparen plugin, but many syntax highlighting plugins\n * mark mismatched brackets as Error.)\n */\n.cm-s-abbott span.CodeMirror-nonmatchingbracket {\n background: #d80450 /* crimson */ !important;\n color: #231c14 /* bistre */ !important;\n}\n\n.cm-s-abbott .CodeMirror-matchingtag,\n.cm-s-abbott .cm-matchhighlight {\n outline: 1px solid #39a78d /* zomp */;\n}\n\n/* Equivalent to Vim's CursorLine group. */\n.cm-s-abbott .CodeMirror-activeline-background,\n.cm-s-abbott .CodeMirror-activeline-gutter {\n background: #3c3022 /* chocolate */;\n}\n\n/* Equivalent to Vim's CursorLineNr group. */\n.cm-s-abbott .CodeMirror-activeline-gutter .CodeMirror-linenumber {\n color: #d8ff84 /* pastel_chartreuse */;\n font-weight: bold;\n}\n\n/* Roughly equivalent to Vim's Folded group. */\n.cm-s-abbott .CodeMirror-foldmarker {\n color: #f63f05 /* cinnabar */;\n text-shadow: none;\n}\n", - 'abcdef': ".cm-s-abcdef.CodeMirror { background: #0f0f0f; color: #defdef; }\n.cm-s-abcdef div.CodeMirror-selected { background: #515151; }\n.cm-s-abcdef .CodeMirror-line::selection, .cm-s-abcdef .CodeMirror-line > span::selection, .cm-s-abcdef .CodeMirror-line > span > span::selection { background: rgba(56, 56, 56, 0.99); }\n.cm-s-abcdef .CodeMirror-line::-moz-selection, .cm-s-abcdef .CodeMirror-line > span::-moz-selection, .cm-s-abcdef .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 56, 56, 0.99); }\n.cm-s-abcdef .CodeMirror-gutters { background: #555; border-right: 2px solid #314151; }\n.cm-s-abcdef .CodeMirror-guttermarker { color: #222; }\n.cm-s-abcdef .CodeMirror-guttermarker-subtle { color: azure; }\n.cm-s-abcdef .CodeMirror-linenumber { color: #FFFFFF; }\n.cm-s-abcdef .CodeMirror-cursor { border-left: 1px solid #00FF00; }\n\n.cm-s-abcdef span.cm-keyword { color: darkgoldenrod; font-weight: bold; }\n.cm-s-abcdef span.cm-atom { color: #77F; }\n.cm-s-abcdef span.cm-number { color: violet; }\n.cm-s-abcdef span.cm-def { color: #fffabc; }\n.cm-s-abcdef span.cm-variable { color: #abcdef; }\n.cm-s-abcdef span.cm-variable-2 { color: #cacbcc; }\n.cm-s-abcdef span.cm-variable-3, .cm-s-abcdef span.cm-type { color: #def; }\n.cm-s-abcdef span.cm-property { color: #fedcba; }\n.cm-s-abcdef span.cm-operator { color: #ff0; }\n.cm-s-abcdef span.cm-comment { color: #7a7b7c; font-style: italic;}\n.cm-s-abcdef span.cm-string { color: #2b4; }\n.cm-s-abcdef span.cm-meta { color: #C9F; }\n.cm-s-abcdef span.cm-qualifier { color: #FFF700; }\n.cm-s-abcdef span.cm-builtin { color: #30aabc; }\n.cm-s-abcdef span.cm-bracket { color: #8a8a8a; }\n.cm-s-abcdef span.cm-tag { color: #FFDD44; }\n.cm-s-abcdef span.cm-attribute { color: #DDFF00; }\n.cm-s-abcdef span.cm-error { color: #FF0000; }\n.cm-s-abcdef span.cm-header { color: aquamarine; font-weight: bold; }\n.cm-s-abcdef span.cm-link { color: blueviolet; }\n\n.cm-s-abcdef .CodeMirror-activeline-background { background: #314151; }\n", - 'ambiance-mobile': ".cm-s-ambiance.CodeMirror {\n -webkit-box-shadow: none;\n -moz-box-shadow: none;\n box-shadow: none;\n}\n", - 'ambiance': "/* ambiance theme for codemirror */\n\n/* Color scheme */\n\n.cm-s-ambiance .cm-header { color: blue; }\n.cm-s-ambiance .cm-quote { color: #24C2C7; }\n\n.cm-s-ambiance .cm-keyword { color: #cda869; }\n.cm-s-ambiance .cm-atom { color: #CF7EA9; }\n.cm-s-ambiance .cm-number { color: #78CF8A; }\n.cm-s-ambiance .cm-def { color: #aac6e3; }\n.cm-s-ambiance .cm-variable { color: #ffb795; }\n.cm-s-ambiance .cm-variable-2 { color: #eed1b3; }\n.cm-s-ambiance .cm-variable-3, .cm-s-ambiance .cm-type { color: #faded3; }\n.cm-s-ambiance .cm-property { color: #eed1b3; }\n.cm-s-ambiance .cm-operator { color: #fa8d6a; }\n.cm-s-ambiance .cm-comment { color: #555; font-style:italic; }\n.cm-s-ambiance .cm-string { color: #8f9d6a; }\n.cm-s-ambiance .cm-string-2 { color: #9d937c; }\n.cm-s-ambiance .cm-meta { color: #D2A8A1; }\n.cm-s-ambiance .cm-qualifier { color: yellow; }\n.cm-s-ambiance .cm-builtin { color: #9999cc; }\n.cm-s-ambiance .cm-bracket { color: #24C2C7; }\n.cm-s-ambiance .cm-tag { color: #fee4ff; }\n.cm-s-ambiance .cm-attribute { color: #9B859D; }\n.cm-s-ambiance .cm-hr { color: pink; }\n.cm-s-ambiance .cm-link { color: #F4C20B; }\n.cm-s-ambiance .cm-special { color: #FF9D00; }\n.cm-s-ambiance .cm-error { color: #AF2018; }\n\n.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }\n.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }\n\n.cm-s-ambiance div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }\n.cm-s-ambiance.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\n.cm-s-ambiance .CodeMirror-line::selection, .cm-s-ambiance .CodeMirror-line > span::selection, .cm-s-ambiance .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\n.cm-s-ambiance .CodeMirror-line::-moz-selection, .cm-s-ambiance .CodeMirror-line > span::-moz-selection, .cm-s-ambiance .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\n\n/* Editor styling */\n\n.cm-s-ambiance.CodeMirror {\n line-height: 1.40em;\n color: #E6E1DC;\n background-color: #202020;\n -webkit-box-shadow: inset 0 0 10px black;\n -moz-box-shadow: inset 0 0 10px black;\n box-shadow: inset 0 0 10px black;\n}\n\n.cm-s-ambiance .CodeMirror-gutters {\n background: #3D3D3D;\n border-right: 1px solid #4D4D4D;\n box-shadow: 0 10px 20px black;\n}\n\n.cm-s-ambiance .CodeMirror-linenumber {\n text-shadow: 0px 1px 1px #4d4d4d;\n color: #111;\n padding: 0 5px;\n}\n\n.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; }\n.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; }\n\n.cm-s-ambiance .CodeMirror-cursor { border-left: 1px solid #7991E8; }\n\n.cm-s-ambiance .CodeMirror-activeline-background {\n background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);\n}\n\n.cm-s-ambiance.CodeMirror,\n.cm-s-ambiance .CodeMirror-gutters {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC\");\n}\n", - 'ayu-dark': "/* Based on https://github.com/dempfi/ayu */\n\n.cm-s-ayu-dark.CodeMirror { background: #0a0e14; color: #b3b1ad; }\n.cm-s-ayu-dark div.CodeMirror-selected { background: #273747; }\n.cm-s-ayu-dark .CodeMirror-line::selection, .cm-s-ayu-dark .CodeMirror-line > span::selection, .cm-s-ayu-dark .CodeMirror-line > span > span::selection { background: rgba(39, 55, 71, 99); }\n.cm-s-ayu-dark .CodeMirror-line::-moz-selection, .cm-s-ayu-dark .CodeMirror-line > span::-moz-selection, .cm-s-ayu-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 55, 71, 99); }\n.cm-s-ayu-dark .CodeMirror-gutters { background: #0a0e14; border-right: 0px; }\n.cm-s-ayu-dark .CodeMirror-guttermarker { color: white; }\n.cm-s-ayu-dark .CodeMirror-guttermarker-subtle { color: #3d424d; }\n.cm-s-ayu-dark .CodeMirror-linenumber { color: #3d424d; }\n.cm-s-ayu-dark .CodeMirror-cursor { border-left: 1px solid #e6b450; }\n.cm-s-ayu-dark.cm-fat-cursor .CodeMirror-cursor { background-color: #a2a8a175 !important; }\n.cm-s-ayu-dark .cm-animate-fat-cursor { background-color: #a2a8a175 !important; }\n\n.cm-s-ayu-dark span.cm-comment { color: #626a73; }\n.cm-s-ayu-dark span.cm-atom { color: #ae81ff; }\n.cm-s-ayu-dark span.cm-number { color: #e6b450; }\n\n.cm-s-ayu-dark span.cm-comment.cm-attribute { color: #ffb454; }\n.cm-s-ayu-dark span.cm-comment.cm-def { color: rgba(57, 186, 230, 80); }\n.cm-s-ayu-dark span.cm-comment.cm-tag { color: #39bae6; }\n.cm-s-ayu-dark span.cm-comment.cm-type { color: #5998a6; }\n\n.cm-s-ayu-dark span.cm-property, .cm-s-ayu-dark span.cm-attribute { color: #ffb454; } \n.cm-s-ayu-dark span.cm-keyword { color: #ff8f40; } \n.cm-s-ayu-dark span.cm-builtin { color: #e6b450; }\n.cm-s-ayu-dark span.cm-string { color: #c2d94c; }\n\n.cm-s-ayu-dark span.cm-variable { color: #b3b1ad; }\n.cm-s-ayu-dark span.cm-variable-2 { color: #f07178; }\n.cm-s-ayu-dark span.cm-variable-3 { color: #39bae6; }\n.cm-s-ayu-dark span.cm-type { color: #ff8f40; }\n.cm-s-ayu-dark span.cm-def { color: #ffee99; }\n.cm-s-ayu-dark span.cm-bracket { color: #f8f8f2; }\n.cm-s-ayu-dark span.cm-tag { color: rgba(57, 186, 230, 80); }\n.cm-s-ayu-dark span.cm-header { color: #c2d94c; }\n.cm-s-ayu-dark span.cm-link { color: #39bae6; }\n.cm-s-ayu-dark span.cm-error { color: #ff3333; } \n\n.cm-s-ayu-dark .CodeMirror-activeline-background { background: #01060e; }\n.cm-s-ayu-dark .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'ayu-mirage': "/* Based on https://github.com/dempfi/ayu */\n\n.cm-s-ayu-mirage.CodeMirror { background: #1f2430; color: #cbccc6; }\n.cm-s-ayu-mirage div.CodeMirror-selected { background: #34455a; }\n.cm-s-ayu-mirage .CodeMirror-line::selection, .cm-s-ayu-mirage .CodeMirror-line > span::selection, .cm-s-ayu-mirage .CodeMirror-line > span > span::selection { background: #34455a; }\n.cm-s-ayu-mirage .CodeMirror-line::-moz-selection, .cm-s-ayu-mirage .CodeMirror-line > span::-moz-selection, .cm-s-ayu-mirage .CodeMirror-line > span > span::-moz-selection { background: rgba(25, 30, 42, 99); }\n.cm-s-ayu-mirage .CodeMirror-gutters { background: #1f2430; border-right: 0px; }\n.cm-s-ayu-mirage .CodeMirror-guttermarker { color: white; }\n.cm-s-ayu-mirage .CodeMirror-guttermarker-subtle { color: rgba(112, 122, 140, 66); }\n.cm-s-ayu-mirage .CodeMirror-linenumber { color: rgba(61, 66, 77, 99); }\n.cm-s-ayu-mirage .CodeMirror-cursor { border-left: 1px solid #ffcc66; }\n.cm-s-ayu-mirage.cm-fat-cursor .CodeMirror-cursor {background-color: #a2a8a175 !important;}\n.cm-s-ayu-mirage .cm-animate-fat-cursor { background-color: #a2a8a175 !important; }\n\n.cm-s-ayu-mirage span.cm-comment { color: #5c6773; font-style:italic; }\n.cm-s-ayu-mirage span.cm-atom { color: #ae81ff; }\n.cm-s-ayu-mirage span.cm-number { color: #ffcc66; }\n\n.cm-s-ayu-mirage span.cm-comment.cm-attribute { color: #ffd580; }\n.cm-s-ayu-mirage span.cm-comment.cm-def { color: #d4bfff; }\n.cm-s-ayu-mirage span.cm-comment.cm-tag { color: #5ccfe6; }\n.cm-s-ayu-mirage span.cm-comment.cm-type { color: #5998a6; }\n\n.cm-s-ayu-mirage span.cm-property { color: #f29e74; }\n.cm-s-ayu-mirage span.cm-attribute { color: #ffd580; } \n.cm-s-ayu-mirage span.cm-keyword { color: #ffa759; } \n.cm-s-ayu-mirage span.cm-builtin { color: #ffcc66; }\n.cm-s-ayu-mirage span.cm-string { color: #bae67e; }\n\n.cm-s-ayu-mirage span.cm-variable { color: #cbccc6; }\n.cm-s-ayu-mirage span.cm-variable-2 { color: #f28779; }\n.cm-s-ayu-mirage span.cm-variable-3 { color: #5ccfe6; }\n.cm-s-ayu-mirage span.cm-type { color: #ffa759; }\n.cm-s-ayu-mirage span.cm-def { color: #ffd580; }\n.cm-s-ayu-mirage span.cm-bracket { color: rgba(92, 207, 230, 80); }\n.cm-s-ayu-mirage span.cm-tag { color: #5ccfe6; }\n.cm-s-ayu-mirage span.cm-header { color: #bae67e; }\n.cm-s-ayu-mirage span.cm-link { color: #5ccfe6; }\n.cm-s-ayu-mirage span.cm-error { color: #ff3333; } \n\n.cm-s-ayu-mirage .CodeMirror-activeline-background { background: #191e2a; }\n.cm-s-ayu-mirage .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'base16-dark': "/*\n\n Name: Base16 Default Dark\n Author: Chris Kempson (http://chriskempson.com)\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-base16-dark.CodeMirror { background: #151515; color: #e0e0e0; }\n.cm-s-base16-dark div.CodeMirror-selected { background: #303030; }\n.cm-s-base16-dark .CodeMirror-line::selection, .cm-s-base16-dark .CodeMirror-line > span::selection, .cm-s-base16-dark .CodeMirror-line > span > span::selection { background: rgba(48, 48, 48, .99); }\n.cm-s-base16-dark .CodeMirror-line::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(48, 48, 48, .99); }\n.cm-s-base16-dark .CodeMirror-gutters { background: #151515; border-right: 0px; }\n.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; }\n.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; }\n.cm-s-base16-dark .CodeMirror-linenumber { color: #505050; }\n.cm-s-base16-dark .CodeMirror-cursor { border-left: 1px solid #b0b0b0; }\n.cm-s-base16-dark.cm-fat-cursor .CodeMirror-cursor { background-color: #8e8d8875 !important; }\n.cm-s-base16-dark .cm-animate-fat-cursor { background-color: #8e8d8875 !important; }\n\n.cm-s-base16-dark span.cm-comment { color: #8f5536; }\n.cm-s-base16-dark span.cm-atom { color: #aa759f; }\n.cm-s-base16-dark span.cm-number { color: #aa759f; }\n\n.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute { color: #90a959; }\n.cm-s-base16-dark span.cm-keyword { color: #ac4142; }\n.cm-s-base16-dark span.cm-string { color: #f4bf75; }\n\n.cm-s-base16-dark span.cm-variable { color: #90a959; }\n.cm-s-base16-dark span.cm-variable-2 { color: #6a9fb5; }\n.cm-s-base16-dark span.cm-def { color: #d28445; }\n.cm-s-base16-dark span.cm-bracket { color: #e0e0e0; }\n.cm-s-base16-dark span.cm-tag { color: #ac4142; }\n.cm-s-base16-dark span.cm-link { color: #aa759f; }\n.cm-s-base16-dark span.cm-error { background: #ac4142; color: #b0b0b0; }\n\n.cm-s-base16-dark .CodeMirror-activeline-background { background: #202020; }\n.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'base16-light': "/*\n\n Name: Base16 Default Light\n Author: Chris Kempson (http://chriskempson.com)\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-base16-light.CodeMirror { background: #f5f5f5; color: #202020; }\n.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; }\n.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }\n.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }\n.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }\n.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }\n.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }\n.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }\n.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }\n\n.cm-s-base16-light span.cm-comment { color: #8f5536; }\n.cm-s-base16-light span.cm-atom { color: #aa759f; }\n.cm-s-base16-light span.cm-number { color: #aa759f; }\n\n.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; }\n.cm-s-base16-light span.cm-keyword { color: #ac4142; }\n.cm-s-base16-light span.cm-string { color: #f4bf75; }\n\n.cm-s-base16-light span.cm-variable { color: #90a959; }\n.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }\n.cm-s-base16-light span.cm-def { color: #d28445; }\n.cm-s-base16-light span.cm-bracket { color: #202020; }\n.cm-s-base16-light span.cm-tag { color: #ac4142; }\n.cm-s-base16-light span.cm-link { color: #aa759f; }\n.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }\n\n.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }\n.cm-s-base16-light .CodeMirror-matchingbracket { color: #f5f5f5 !important; background-color: #6A9FB5 !important}\n", - 'bespin': "/*\n\n Name: Bespin\n Author: Mozilla / Jan T. Sott\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-bespin.CodeMirror {background: #28211c; color: #9d9b97;}\n.cm-s-bespin div.CodeMirror-selected {background: #36312e !important;}\n.cm-s-bespin .CodeMirror-gutters {background: #28211c; border-right: 0px;}\n.cm-s-bespin .CodeMirror-linenumber {color: #666666;}\n.cm-s-bespin .CodeMirror-cursor {border-left: 1px solid #797977 !important;}\n\n.cm-s-bespin span.cm-comment {color: #937121;}\n.cm-s-bespin span.cm-atom {color: #9b859d;}\n.cm-s-bespin span.cm-number {color: #9b859d;}\n\n.cm-s-bespin span.cm-property, .cm-s-bespin span.cm-attribute {color: #54be0d;}\n.cm-s-bespin span.cm-keyword {color: #cf6a4c;}\n.cm-s-bespin span.cm-string {color: #f9ee98;}\n\n.cm-s-bespin span.cm-variable {color: #54be0d;}\n.cm-s-bespin span.cm-variable-2 {color: #5ea6ea;}\n.cm-s-bespin span.cm-def {color: #cf7d34;}\n.cm-s-bespin span.cm-error {background: #cf6a4c; color: #797977;}\n.cm-s-bespin span.cm-bracket {color: #9d9b97;}\n.cm-s-bespin span.cm-tag {color: #cf6a4c;}\n.cm-s-bespin span.cm-link {color: #9b859d;}\n\n.cm-s-bespin .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n.cm-s-bespin .CodeMirror-activeline-background { background: #404040; }\n", - 'blackboard': "/* Port of TextMate's Blackboard theme */\n\n.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; }\n.cm-s-blackboard div.CodeMirror-selected { background: #253B76; }\n.cm-s-blackboard .CodeMirror-line::selection, .cm-s-blackboard .CodeMirror-line > span::selection, .cm-s-blackboard .CodeMirror-line > span > span::selection { background: rgba(37, 59, 118, .99); }\n.cm-s-blackboard .CodeMirror-line::-moz-selection, .cm-s-blackboard .CodeMirror-line > span::-moz-selection, .cm-s-blackboard .CodeMirror-line > span > span::-moz-selection { background: rgba(37, 59, 118, .99); }\n.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; }\n.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; }\n.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; }\n.cm-s-blackboard .CodeMirror-linenumber { color: #888; }\n.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }\n\n.cm-s-blackboard .cm-keyword { color: #FBDE2D; }\n.cm-s-blackboard .cm-atom { color: #D8FA3C; }\n.cm-s-blackboard .cm-number { color: #D8FA3C; }\n.cm-s-blackboard .cm-def { color: #8DA6CE; }\n.cm-s-blackboard .cm-variable { color: #FF6400; }\n.cm-s-blackboard .cm-operator { color: #FBDE2D; }\n.cm-s-blackboard .cm-comment { color: #AEAEAE; }\n.cm-s-blackboard .cm-string { color: #61CE3C; }\n.cm-s-blackboard .cm-string-2 { color: #61CE3C; }\n.cm-s-blackboard .cm-meta { color: #D8FA3C; }\n.cm-s-blackboard .cm-builtin { color: #8DA6CE; }\n.cm-s-blackboard .cm-tag { color: #8DA6CE; }\n.cm-s-blackboard .cm-attribute { color: #8DA6CE; }\n.cm-s-blackboard .cm-header { color: #FF6400; }\n.cm-s-blackboard .cm-hr { color: #AEAEAE; }\n.cm-s-blackboard .cm-link { color: #8DA6CE; }\n.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }\n\n.cm-s-blackboard .CodeMirror-activeline-background { background: #3C3636; }\n.cm-s-blackboard .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }\n", - 'cobalt': ".cm-s-cobalt.CodeMirror { background: #002240; color: white; }\n.cm-s-cobalt div.CodeMirror-selected { background: #b36539; }\n.cm-s-cobalt .CodeMirror-line::selection, .cm-s-cobalt .CodeMirror-line > span::selection, .cm-s-cobalt .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }\n.cm-s-cobalt .CodeMirror-line::-moz-selection, .cm-s-cobalt .CodeMirror-line > span::-moz-selection, .cm-s-cobalt .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }\n.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\n.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; }\n.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-cobalt span.cm-comment { color: #08f; }\n.cm-s-cobalt span.cm-atom { color: #845dc4; }\n.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }\n.cm-s-cobalt span.cm-keyword { color: #ffee80; }\n.cm-s-cobalt span.cm-string { color: #3ad900; }\n.cm-s-cobalt span.cm-meta { color: #ff9d00; }\n.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }\n.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def, .cm-s-cobalt .cm-type { color: white; }\n.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }\n.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }\n.cm-s-cobalt span.cm-link { color: #845dc4; }\n.cm-s-cobalt span.cm-error { color: #9d1e15; }\n\n.cm-s-cobalt .CodeMirror-activeline-background { background: #002D57; }\n.cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }\n", - 'colorforth': ".cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; }\n.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\n.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; }\n.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; }\n.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; }\n.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-colorforth span.cm-comment { color: #ededed; }\n.cm-s-colorforth span.cm-def { color: #ff1c1c; font-weight:bold; }\n.cm-s-colorforth span.cm-keyword { color: #ffd900; }\n.cm-s-colorforth span.cm-builtin { color: #00d95a; }\n.cm-s-colorforth span.cm-variable { color: #73ff00; }\n.cm-s-colorforth span.cm-string { color: #007bff; }\n.cm-s-colorforth span.cm-number { color: #00c4ff; }\n.cm-s-colorforth span.cm-atom { color: #606060; }\n\n.cm-s-colorforth span.cm-variable-2 { color: #EEE; }\n.cm-s-colorforth span.cm-variable-3, .cm-s-colorforth span.cm-type { color: #DDD; }\n.cm-s-colorforth span.cm-property {}\n.cm-s-colorforth span.cm-operator {}\n\n.cm-s-colorforth span.cm-meta { color: yellow; }\n.cm-s-colorforth span.cm-qualifier { color: #FFF700; }\n.cm-s-colorforth span.cm-bracket { color: #cc7; }\n.cm-s-colorforth span.cm-tag { color: #FFBD40; }\n.cm-s-colorforth span.cm-attribute { color: #FFF700; }\n.cm-s-colorforth span.cm-error { color: #f00; }\n\n.cm-s-colorforth div.CodeMirror-selected { background: #333d53; }\n\n.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); }\n\n.cm-s-colorforth .CodeMirror-activeline-background { background: #253540; }\n", - 'darcula': "/**\n Name: IntelliJ IDEA darcula theme\n From IntelliJ IDEA by JetBrains\n */\n\n.cm-s-darcula { font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif;}\n.cm-s-darcula.CodeMirror { background: #2B2B2B; color: #A9B7C6; }\n\n.cm-s-darcula span.cm-meta { color: #BBB529; }\n.cm-s-darcula span.cm-number { color: #6897BB; }\n.cm-s-darcula span.cm-keyword { color: #CC7832; line-height: 1em; font-weight: bold; }\n.cm-s-darcula span.cm-def { color: #A9B7C6; font-style: italic; }\n.cm-s-darcula span.cm-variable { color: #A9B7C6; }\n.cm-s-darcula span.cm-variable-2 { color: #A9B7C6; }\n.cm-s-darcula span.cm-variable-3 { color: #9876AA; }\n.cm-s-darcula span.cm-type { color: #AABBCC; font-weight: bold; }\n.cm-s-darcula span.cm-property { color: #FFC66D; }\n.cm-s-darcula span.cm-operator { color: #A9B7C6; }\n.cm-s-darcula span.cm-string { color: #6A8759; }\n.cm-s-darcula span.cm-string-2 { color: #6A8759; }\n.cm-s-darcula span.cm-comment { color: #61A151; font-style: italic; }\n.cm-s-darcula span.cm-link { color: #CC7832; }\n.cm-s-darcula span.cm-atom { color: #CC7832; }\n.cm-s-darcula span.cm-error { color: #BC3F3C; }\n.cm-s-darcula span.cm-tag { color: #629755; font-weight: bold; font-style: italic; text-decoration: underline; }\n.cm-s-darcula span.cm-attribute { color: #6897bb; }\n.cm-s-darcula span.cm-qualifier { color: #6A8759; }\n.cm-s-darcula span.cm-bracket { color: #A9B7C6; }\n.cm-s-darcula span.cm-builtin { color: #FF9E59; }\n.cm-s-darcula span.cm-special { color: #FF9E59; }\n.cm-s-darcula span.cm-matchhighlight { color: #FFFFFF; background-color: rgba(50, 89, 48, .7); font-weight: normal;}\n.cm-s-darcula span.cm-searching { color: #FFFFFF; background-color: rgba(61, 115, 59, .7); font-weight: normal;}\n\n.cm-s-darcula .CodeMirror-cursor { border-left: 1px solid #A9B7C6; }\n.cm-s-darcula .CodeMirror-activeline-background { background: #323232; }\n.cm-s-darcula .CodeMirror-gutters { background: #313335; border-right: 1px solid #313335; }\n.cm-s-darcula .CodeMirror-guttermarker { color: #FFEE80; }\n.cm-s-darcula .CodeMirror-guttermarker-subtle { color: #D0D0D0; }\n.cm-s-darcula .CodeMirrir-linenumber { color: #606366; }\n.cm-s-darcula .CodeMirror-matchingbracket { background-color: #3B514D; color: #FFEF28 !important; font-weight: bold; }\n\n.cm-s-darcula div.CodeMirror-selected { background: #214283; }\n\n.CodeMirror-hints.darcula {\n font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;\n color: #9C9E9E;\n background-color: #3B3E3F !important;\n}\n\n.CodeMirror-hints.darcula .CodeMirror-hint-active {\n background-color: #494D4E !important;\n color: #9C9E9E !important;\n}\n", - 'dracula': "/*\n\n Name: dracula\n Author: Michael Kaminsky (http://github.com/mkaminsky11)\n\n Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)\n\n*/\n\n\n.cm-s-dracula.CodeMirror, .cm-s-dracula .CodeMirror-gutters {\n background-color: #282a36 !important;\n color: #f8f8f2 !important;\n border: none;\n}\n.cm-s-dracula .CodeMirror-gutters { color: #282a36; }\n.cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; }\n.cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; }\n.cm-s-dracula .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\n.cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\n.cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\n.cm-s-dracula span.cm-comment { color: #6272a4; }\n.cm-s-dracula span.cm-string, .cm-s-dracula span.cm-string-2 { color: #f1fa8c; }\n.cm-s-dracula span.cm-number { color: #bd93f9; }\n.cm-s-dracula span.cm-variable { color: #50fa7b; }\n.cm-s-dracula span.cm-variable-2 { color: white; }\n.cm-s-dracula span.cm-def { color: #50fa7b; }\n.cm-s-dracula span.cm-operator { color: #ff79c6; }\n.cm-s-dracula span.cm-keyword { color: #ff79c6; }\n.cm-s-dracula span.cm-atom { color: #bd93f9; }\n.cm-s-dracula span.cm-meta { color: #f8f8f2; }\n.cm-s-dracula span.cm-tag { color: #ff79c6; }\n.cm-s-dracula span.cm-attribute { color: #50fa7b; }\n.cm-s-dracula span.cm-qualifier { color: #50fa7b; }\n.cm-s-dracula span.cm-property { color: #66d9ef; }\n.cm-s-dracula span.cm-builtin { color: #50fa7b; }\n.cm-s-dracula span.cm-variable-3, .cm-s-dracula span.cm-type { color: #ffb86c; }\n\n.cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); }\n.cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'duotone-dark': "/*\nName: DuoTone-Dark\nAuthor: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)\n\nCodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/)\n*/\n\n.cm-s-duotone-dark.CodeMirror { background: #2a2734; color: #6c6783; }\n.cm-s-duotone-dark div.CodeMirror-selected { background: #545167!important; }\n.cm-s-duotone-dark .CodeMirror-gutters { background: #2a2734; border-right: 0px; }\n.cm-s-duotone-dark .CodeMirror-linenumber { color: #545167; }\n\n/* begin cursor */\n.cm-s-duotone-dark .CodeMirror-cursor { border-left: 1px solid #ffad5c; /* border-left: 1px solid #ffad5c80; */ border-right: .5em solid #ffad5c; /* border-right: .5em solid #ffad5c80; */ opacity: .5; }\n.cm-s-duotone-dark .CodeMirror-activeline-background { background: #363342; /* background: #36334280; */ opacity: .5;}\n.cm-s-duotone-dark .cm-fat-cursor .CodeMirror-cursor { background: #ffad5c; /* background: #ffad5c80; */ opacity: .5;}\n/* end cursor */\n\n.cm-s-duotone-dark span.cm-atom, .cm-s-duotone-dark span.cm-number, .cm-s-duotone-dark span.cm-keyword, .cm-s-duotone-dark span.cm-variable, .cm-s-duotone-dark span.cm-attribute, .cm-s-duotone-dark span.cm-quote, .cm-s-duotone-dark span.cm-hr, .cm-s-duotone-dark span.cm-link { color: #ffcc99; }\n\n.cm-s-duotone-dark span.cm-property { color: #9a86fd; }\n.cm-s-duotone-dark span.cm-punctuation, .cm-s-duotone-dark span.cm-unit, .cm-s-duotone-dark span.cm-negative { color: #e09142; }\n.cm-s-duotone-dark span.cm-string { color: #ffb870; }\n.cm-s-duotone-dark span.cm-operator { color: #ffad5c; }\n.cm-s-duotone-dark span.cm-positive { color: #6a51e6; }\n\n.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-type, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; }\n.cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; }\n.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; }\n\n/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */\n.cm-s-duotone-dark span.cm-error, .cm-s-duotone-dark span.cm-invalidchar { color: #f00; }\n\n.cm-s-duotone-dark span.cm-header { font-weight: normal; }\n.cm-s-duotone-dark .CodeMirror-matchingbracket { text-decoration: underline; color: #eeebff !important; } \n", - 'duotone-light': "/*\nName: DuoTone-Light\nAuthor: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)\n\nCodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/)\n*/\n\n.cm-s-duotone-light.CodeMirror { background: #faf8f5; color: #b29762; }\n.cm-s-duotone-light div.CodeMirror-selected { background: #e3dcce !important; }\n.cm-s-duotone-light .CodeMirror-gutters { background: #faf8f5; border-right: 0px; }\n.cm-s-duotone-light .CodeMirror-linenumber { color: #cdc4b1; }\n\n/* begin cursor */\n.cm-s-duotone-light .CodeMirror-cursor { border-left: 1px solid #93abdc; /* border-left: 1px solid #93abdc80; */ border-right: .5em solid #93abdc; /* border-right: .5em solid #93abdc80; */ opacity: .5; }\n.cm-s-duotone-light .CodeMirror-activeline-background { background: #e3dcce; /* background: #e3dcce80; */ opacity: .5; }\n.cm-s-duotone-light .cm-fat-cursor .CodeMirror-cursor { background: #93abdc; /* #93abdc80; */ opacity: .5; }\n/* end cursor */\n\n.cm-s-duotone-light span.cm-atom, .cm-s-duotone-light span.cm-number, .cm-s-duotone-light span.cm-keyword, .cm-s-duotone-light span.cm-variable, .cm-s-duotone-light span.cm-attribute, .cm-s-duotone-light span.cm-quote, .cm-s-duotone-light-light span.cm-hr, .cm-s-duotone-light-light span.cm-link { color: #063289; }\n\n.cm-s-duotone-light span.cm-property { color: #b29762; }\n.cm-s-duotone-light span.cm-punctuation, .cm-s-duotone-light span.cm-unit, .cm-s-duotone-light span.cm-negative { color: #063289; }\n.cm-s-duotone-light span.cm-string, .cm-s-duotone-light span.cm-operator { color: #1659df; }\n.cm-s-duotone-light span.cm-positive { color: #896724; }\n\n.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-type, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; }\n.cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; }\n.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; }\n\n/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */\n/* .cm-s-duotone-light span.cm-error { background: #896724; color: #728fcb; } */\n.cm-s-duotone-light span.cm-error, .cm-s-duotone-light span.cm-invalidchar { color: #f00; }\n\n.cm-s-duotone-light span.cm-header { font-weight: normal; }\n.cm-s-duotone-light .CodeMirror-matchingbracket { text-decoration: underline; color: #faf8f5 !important; }\n\n", - 'eclipse': ".cm-s-eclipse span.cm-meta { color: #FF1717; }\n.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }\n.cm-s-eclipse span.cm-atom { color: #219; }\n.cm-s-eclipse span.cm-number { color: #164; }\n.cm-s-eclipse span.cm-def { color: #00f; }\n.cm-s-eclipse span.cm-variable { color: black; }\n.cm-s-eclipse span.cm-variable-2 { color: #0000C0; }\n.cm-s-eclipse span.cm-variable-3, .cm-s-eclipse span.cm-type { color: #0000C0; }\n.cm-s-eclipse span.cm-property { color: black; }\n.cm-s-eclipse span.cm-operator { color: black; }\n.cm-s-eclipse span.cm-comment { color: #3F7F5F; }\n.cm-s-eclipse span.cm-string { color: #2A00FF; }\n.cm-s-eclipse span.cm-string-2 { color: #f50; }\n.cm-s-eclipse span.cm-qualifier { color: #555; }\n.cm-s-eclipse span.cm-builtin { color: #30a; }\n.cm-s-eclipse span.cm-bracket { color: #cc7; }\n.cm-s-eclipse span.cm-tag { color: #170; }\n.cm-s-eclipse span.cm-attribute { color: #00c; }\n.cm-s-eclipse span.cm-link { color: #219; }\n.cm-s-eclipse span.cm-error { color: #f00; }\n\n.cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; }\n.cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\n", - 'elegant': ".cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; }\n.cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; }\n.cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; }\n.cm-s-elegant span.cm-variable { color: black; }\n.cm-s-elegant span.cm-variable-2 { color: #b11; }\n.cm-s-elegant span.cm-qualifier { color: #555; }\n.cm-s-elegant span.cm-keyword { color: #730; }\n.cm-s-elegant span.cm-builtin { color: #30a; }\n.cm-s-elegant span.cm-link { color: #762; }\n.cm-s-elegant span.cm-error { background-color: #fdd; }\n\n.cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; }\n.cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\n", - 'erlang-dark': ".cm-s-erlang-dark.CodeMirror { background: #002240; color: white; }\n.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539; }\n.cm-s-erlang-dark .CodeMirror-line::selection, .cm-s-erlang-dark .CodeMirror-line > span::selection, .cm-s-erlang-dark .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }\n.cm-s-erlang-dark .CodeMirror-line::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }\n.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\n.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; }\n.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-erlang-dark span.cm-quote { color: #ccc; }\n.cm-s-erlang-dark span.cm-atom { color: #f133f1; }\n.cm-s-erlang-dark span.cm-attribute { color: #ff80e1; }\n.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; }\n.cm-s-erlang-dark span.cm-builtin { color: #eaa; }\n.cm-s-erlang-dark span.cm-comment { color: #77f; }\n.cm-s-erlang-dark span.cm-def { color: #e7a; }\n.cm-s-erlang-dark span.cm-keyword { color: #ffee80; }\n.cm-s-erlang-dark span.cm-meta { color: #50fefe; }\n.cm-s-erlang-dark span.cm-number { color: #ffd0d0; }\n.cm-s-erlang-dark span.cm-operator { color: #d55; }\n.cm-s-erlang-dark span.cm-property { color: #ccc; }\n.cm-s-erlang-dark span.cm-qualifier { color: #ccc; }\n.cm-s-erlang-dark span.cm-special { color: #ffbbbb; }\n.cm-s-erlang-dark span.cm-string { color: #3ad900; }\n.cm-s-erlang-dark span.cm-string-2 { color: #ccc; }\n.cm-s-erlang-dark span.cm-tag { color: #9effff; }\n.cm-s-erlang-dark span.cm-variable { color: #50fe50; }\n.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }\n.cm-s-erlang-dark span.cm-variable-3, .cm-s-erlang-dark span.cm-type { color: #ccc; }\n.cm-s-erlang-dark span.cm-error { color: #9d1e15; }\n\n.cm-s-erlang-dark .CodeMirror-activeline-background { background: #013461; }\n.cm-s-erlang-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\n", - 'gruvbox-dark': "/*\n\n Name: gruvbox-dark\n Author: kRkk (https://github.com/krkk)\n\n Original gruvbox color scheme by Pavel Pertsev (https://github.com/morhetz/gruvbox)\n\n*/\n\n.cm-s-gruvbox-dark.CodeMirror, .cm-s-gruvbox-dark .CodeMirror-gutters { background-color: #282828; color: #bdae93; }\n.cm-s-gruvbox-dark .CodeMirror-gutters {background: #282828; border-right: 0px;}\n.cm-s-gruvbox-dark .CodeMirror-linenumber {color: #7c6f64;}\n.cm-s-gruvbox-dark .CodeMirror-cursor { border-left: 1px solid #ebdbb2; }\n.cm-s-gruvbox-dark.cm-fat-cursor .CodeMirror-cursor { background-color: #8e8d8875 !important; }\n.cm-s-gruvbox-dark .cm-animate-fat-cursor { background-color: #8e8d8875 !important; }\n.cm-s-gruvbox-dark div.CodeMirror-selected { background: #928374; }\n.cm-s-gruvbox-dark span.cm-meta { color: #83a598; }\n\n.cm-s-gruvbox-dark span.cm-comment { color: #928374; }\n.cm-s-gruvbox-dark span.cm-number, span.cm-atom { color: #d3869b; }\n.cm-s-gruvbox-dark span.cm-keyword { color: #f84934; }\n\n.cm-s-gruvbox-dark span.cm-variable { color: #ebdbb2; }\n.cm-s-gruvbox-dark span.cm-variable-2 { color: #ebdbb2; }\n.cm-s-gruvbox-dark span.cm-variable-3, .cm-s-gruvbox-dark span.cm-type { color: #fabd2f; }\n.cm-s-gruvbox-dark span.cm-operator { color: #ebdbb2; }\n.cm-s-gruvbox-dark span.cm-callee { color: #ebdbb2; }\n.cm-s-gruvbox-dark span.cm-def { color: #ebdbb2; }\n.cm-s-gruvbox-dark span.cm-property { color: #ebdbb2; }\n.cm-s-gruvbox-dark span.cm-string { color: #b8bb26; }\n.cm-s-gruvbox-dark span.cm-string-2 { color: #8ec07c; }\n.cm-s-gruvbox-dark span.cm-qualifier { color: #8ec07c; }\n.cm-s-gruvbox-dark span.cm-attribute { color: #8ec07c; }\n\n.cm-s-gruvbox-dark .CodeMirror-activeline-background { background: #3c3836; }\n.cm-s-gruvbox-dark .CodeMirror-matchingbracket { background: #928374; color:#282828 !important; }\n\n.cm-s-gruvbox-dark span.cm-builtin { color: #fe8019; }\n.cm-s-gruvbox-dark span.cm-tag { color: #fe8019; }\n", - 'hopscotch': "/*\n\n Name: Hopscotch\n Author: Jan T. Sott\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-hopscotch.CodeMirror {background: #322931; color: #d5d3d5;}\n.cm-s-hopscotch div.CodeMirror-selected {background: #433b42 !important;}\n.cm-s-hopscotch .CodeMirror-gutters {background: #322931; border-right: 0px;}\n.cm-s-hopscotch .CodeMirror-linenumber {color: #797379;}\n.cm-s-hopscotch .CodeMirror-cursor {border-left: 1px solid #989498 !important;}\n\n.cm-s-hopscotch span.cm-comment {color: #b33508;}\n.cm-s-hopscotch span.cm-atom {color: #c85e7c;}\n.cm-s-hopscotch span.cm-number {color: #c85e7c;}\n\n.cm-s-hopscotch span.cm-property, .cm-s-hopscotch span.cm-attribute {color: #8fc13e;}\n.cm-s-hopscotch span.cm-keyword {color: #dd464c;}\n.cm-s-hopscotch span.cm-string {color: #fdcc59;}\n\n.cm-s-hopscotch span.cm-variable {color: #8fc13e;}\n.cm-s-hopscotch span.cm-variable-2 {color: #1290bf;}\n.cm-s-hopscotch span.cm-def {color: #fd8b19;}\n.cm-s-hopscotch span.cm-error {background: #dd464c; color: #989498;}\n.cm-s-hopscotch span.cm-bracket {color: #d5d3d5;}\n.cm-s-hopscotch span.cm-tag {color: #dd464c;}\n.cm-s-hopscotch span.cm-link {color: #c85e7c;}\n\n.cm-s-hopscotch .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n.cm-s-hopscotch .CodeMirror-activeline-background { background: #302020; }\n", - 'icecoder': "/*\nICEcoder default theme by Matt Pass, used in code editor available at https://icecoder.net\n*/\n\n.cm-s-icecoder { color: #666; background: #1d1d1b; }\n\n.cm-s-icecoder span.cm-keyword { color: #eee; font-weight:bold; } /* off-white 1 */\n.cm-s-icecoder span.cm-atom { color: #e1c76e; } /* yellow */\n.cm-s-icecoder span.cm-number { color: #6cb5d9; } /* blue */\n.cm-s-icecoder span.cm-def { color: #b9ca4a; } /* green */\n\n.cm-s-icecoder span.cm-variable { color: #6cb5d9; } /* blue */\n.cm-s-icecoder span.cm-variable-2 { color: #cc1e5c; } /* pink */\n.cm-s-icecoder span.cm-variable-3, .cm-s-icecoder span.cm-type { color: #f9602c; } /* orange */\n\n.cm-s-icecoder span.cm-property { color: #eee; } /* off-white 1 */\n.cm-s-icecoder span.cm-operator { color: #9179bb; } /* purple */\n.cm-s-icecoder span.cm-comment { color: #97a3aa; } /* grey-blue */\n\n.cm-s-icecoder span.cm-string { color: #b9ca4a; } /* green */\n.cm-s-icecoder span.cm-string-2 { color: #6cb5d9; } /* blue */\n\n.cm-s-icecoder span.cm-meta { color: #555; } /* grey */\n\n.cm-s-icecoder span.cm-qualifier { color: #555; } /* grey */\n.cm-s-icecoder span.cm-builtin { color: #214e7b; } /* bright blue */\n.cm-s-icecoder span.cm-bracket { color: #cc7; } /* grey-yellow */\n\n.cm-s-icecoder span.cm-tag { color: #e8e8e8; } /* off-white 2 */\n.cm-s-icecoder span.cm-attribute { color: #099; } /* teal */\n\n.cm-s-icecoder span.cm-header { color: #6a0d6a; } /* purple-pink */\n.cm-s-icecoder span.cm-quote { color: #186718; } /* dark green */\n.cm-s-icecoder span.cm-hr { color: #888; } /* mid-grey */\n.cm-s-icecoder span.cm-link { color: #e1c76e; } /* yellow */\n.cm-s-icecoder span.cm-error { color: #d00; } /* red */\n\n.cm-s-icecoder .CodeMirror-cursor { border-left: 1px solid white; }\n.cm-s-icecoder div.CodeMirror-selected { color: #fff; background: #037; }\n.cm-s-icecoder .CodeMirror-gutters { background: #1d1d1b; min-width: 41px; border-right: 0; }\n.cm-s-icecoder .CodeMirror-linenumber { color: #555; cursor: default; }\n.cm-s-icecoder .CodeMirror-matchingbracket { color: #fff !important; background: #555 !important; }\n.cm-s-icecoder .CodeMirror-activeline-background { background: #000; }\n", - 'idea': "/**\n Name: IDEA default theme\n From IntelliJ IDEA by JetBrains\n */\n\n.cm-s-idea span.cm-meta { color: #808000; }\n.cm-s-idea span.cm-number { color: #0000FF; }\n.cm-s-idea span.cm-keyword { line-height: 1em; font-weight: bold; color: #000080; }\n.cm-s-idea span.cm-atom { font-weight: bold; color: #000080; }\n.cm-s-idea span.cm-def { color: #000000; }\n.cm-s-idea span.cm-variable { color: black; }\n.cm-s-idea span.cm-variable-2 { color: black; }\n.cm-s-idea span.cm-variable-3, .cm-s-idea span.cm-type { color: black; }\n.cm-s-idea span.cm-property { color: black; }\n.cm-s-idea span.cm-operator { color: black; }\n.cm-s-idea span.cm-comment { color: #808080; }\n.cm-s-idea span.cm-string { color: #008000; }\n.cm-s-idea span.cm-string-2 { color: #008000; }\n.cm-s-idea span.cm-qualifier { color: #555; }\n.cm-s-idea span.cm-error { color: #FF0000; }\n.cm-s-idea span.cm-attribute { color: #0000FF; }\n.cm-s-idea span.cm-tag { color: #000080; }\n.cm-s-idea span.cm-link { color: #0000FF; }\n.cm-s-idea .CodeMirror-activeline-background { background: #FFFAE3; }\n\n.cm-s-idea span.cm-builtin { color: #30a; }\n.cm-s-idea span.cm-bracket { color: #cc7; }\n.cm-s-idea { font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;}\n\n\n.cm-s-idea .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\n\n.CodeMirror-hints.idea {\n font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;\n color: #616569;\n background-color: #ebf3fd !important;\n}\n\n.CodeMirror-hints.idea .CodeMirror-hint-active {\n background-color: #a2b8c9 !important;\n color: #5c6065 !important;\n}", - 'isotope': "/*\n\n Name: Isotope\n Author: David Desandro / Jan T. Sott\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-isotope.CodeMirror {background: #000000; color: #e0e0e0;}\n.cm-s-isotope div.CodeMirror-selected {background: #404040 !important;}\n.cm-s-isotope .CodeMirror-gutters {background: #000000; border-right: 0px;}\n.cm-s-isotope .CodeMirror-linenumber {color: #808080;}\n.cm-s-isotope .CodeMirror-cursor {border-left: 1px solid #c0c0c0 !important;}\n\n.cm-s-isotope span.cm-comment {color: #3300ff;}\n.cm-s-isotope span.cm-atom {color: #cc00ff;}\n.cm-s-isotope span.cm-number {color: #cc00ff;}\n\n.cm-s-isotope span.cm-property, .cm-s-isotope span.cm-attribute {color: #33ff00;}\n.cm-s-isotope span.cm-keyword {color: #ff0000;}\n.cm-s-isotope span.cm-string {color: #ff0099;}\n\n.cm-s-isotope span.cm-variable {color: #33ff00;}\n.cm-s-isotope span.cm-variable-2 {color: #0066ff;}\n.cm-s-isotope span.cm-def {color: #ff9900;}\n.cm-s-isotope span.cm-error {background: #ff0000; color: #c0c0c0;}\n.cm-s-isotope span.cm-bracket {color: #e0e0e0;}\n.cm-s-isotope span.cm-tag {color: #ff0000;}\n.cm-s-isotope span.cm-link {color: #cc00ff;}\n\n.cm-s-isotope .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n.cm-s-isotope .CodeMirror-activeline-background { background: #202020; }\n", - 'juejin': ".cm-s-juejin.CodeMirror {\n background: #f8f9fa;\n}\n.cm-s-juejin .cm-header,\n.cm-s-juejin .cm-def {\n color: #1ba2f0;\n}\n.cm-s-juejin .cm-comment {\n color: #009e9d;\n}\n.cm-s-juejin .cm-quote,\n.cm-s-juejin .cm-link,\n.cm-s-juejin .cm-strong,\n.cm-s-juejin .cm-attribute {\n color: #fd7741;\n}\n.cm-s-juejin .cm-url,\n.cm-s-juejin .cm-keyword,\n.cm-s-juejin .cm-builtin {\n color: #bb51b8;\n}\n.cm-s-juejin .cm-hr {\n color: #909090;\n}\n.cm-s-juejin .cm-tag {\n color: #107000;\n}\n.cm-s-juejin .cm-variable-2 {\n color: #0050a0;\n}\n", - 'lesser-dark': "/*\nhttp://lesscss.org/ dark theme\nPorted to CodeMirror by Peter Kroon\n*/\n.cm-s-lesser-dark {\n line-height: 1.3em;\n}\n.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }\n.cm-s-lesser-dark div.CodeMirror-selected { background: #45443B; } /* 33322B*/\n.cm-s-lesser-dark .CodeMirror-line::selection, .cm-s-lesser-dark .CodeMirror-line > span::selection, .cm-s-lesser-dark .CodeMirror-line > span > span::selection { background: rgba(69, 68, 59, .99); }\n.cm-s-lesser-dark .CodeMirror-line::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(69, 68, 59, .99); }\n.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white; }\n.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/\n\n.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/\n\n.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; }\n.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; }\n.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; }\n.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; }\n\n.cm-s-lesser-dark span.cm-header { color: #a0a; }\n.cm-s-lesser-dark span.cm-quote { color: #090; }\n.cm-s-lesser-dark span.cm-keyword { color: #599eff; }\n.cm-s-lesser-dark span.cm-atom { color: #C2B470; }\n.cm-s-lesser-dark span.cm-number { color: #B35E4D; }\n.cm-s-lesser-dark span.cm-def { color: white; }\n.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }\n.cm-s-lesser-dark span.cm-variable-2 { color: #669199; }\n.cm-s-lesser-dark span.cm-variable-3, .cm-s-lesser-dark span.cm-type { color: white; }\n.cm-s-lesser-dark span.cm-property { color: #92A75C; }\n.cm-s-lesser-dark span.cm-operator { color: #92A75C; }\n.cm-s-lesser-dark span.cm-comment { color: #666; }\n.cm-s-lesser-dark span.cm-string { color: #BCD279; }\n.cm-s-lesser-dark span.cm-string-2 { color: #f50; }\n.cm-s-lesser-dark span.cm-meta { color: #738C73; }\n.cm-s-lesser-dark span.cm-qualifier { color: #555; }\n.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }\n.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }\n.cm-s-lesser-dark span.cm-tag { color: #669199; }\n.cm-s-lesser-dark span.cm-attribute { color: #81a4d5; }\n.cm-s-lesser-dark span.cm-hr { color: #999; }\n.cm-s-lesser-dark span.cm-link { color: #7070E6; }\n.cm-s-lesser-dark span.cm-error { color: #9d1e15; }\n\n.cm-s-lesser-dark .CodeMirror-activeline-background { background: #3C3A3A; }\n.cm-s-lesser-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\n", - 'liquibyte': ".cm-s-liquibyte.CodeMirror {\n\tbackground-color: #000;\n\tcolor: #fff;\n\tline-height: 1.2em;\n\tfont-size: 1em;\n}\n.cm-s-liquibyte .CodeMirror-focused .cm-matchhighlight {\n\ttext-decoration: underline;\n\ttext-decoration-color: #0f0;\n\ttext-decoration-style: wavy;\n}\n.cm-s-liquibyte .cm-trailingspace {\n\ttext-decoration: line-through;\n\ttext-decoration-color: #f00;\n\ttext-decoration-style: dotted;\n}\n.cm-s-liquibyte .cm-tab {\n\ttext-decoration: line-through;\n\ttext-decoration-color: #404040;\n\ttext-decoration-style: dotted;\n}\n.cm-s-liquibyte .CodeMirror-gutters { background-color: #262626; border-right: 1px solid #505050; padding-right: 0.8em; }\n.cm-s-liquibyte .CodeMirror-gutter-elt div { font-size: 1.2em; }\n.cm-s-liquibyte .CodeMirror-guttermarker { }\n.cm-s-liquibyte .CodeMirror-guttermarker-subtle { }\n.cm-s-liquibyte .CodeMirror-linenumber { color: #606060; padding-left: 0; }\n.cm-s-liquibyte .CodeMirror-cursor { border-left: 1px solid #eee; }\n\n.cm-s-liquibyte span.cm-comment { color: #008000; }\n.cm-s-liquibyte span.cm-def { color: #ffaf40; font-weight: bold; }\n.cm-s-liquibyte span.cm-keyword { color: #c080ff; font-weight: bold; }\n.cm-s-liquibyte span.cm-builtin { color: #ffaf40; font-weight: bold; }\n.cm-s-liquibyte span.cm-variable { color: #5967ff; font-weight: bold; }\n.cm-s-liquibyte span.cm-string { color: #ff8000; }\n.cm-s-liquibyte span.cm-number { color: #0f0; font-weight: bold; }\n.cm-s-liquibyte span.cm-atom { color: #bf3030; font-weight: bold; }\n\n.cm-s-liquibyte span.cm-variable-2 { color: #007f7f; font-weight: bold; }\n.cm-s-liquibyte span.cm-variable-3, .cm-s-liquibyte span.cm-type { color: #c080ff; font-weight: bold; }\n.cm-s-liquibyte span.cm-property { color: #999; font-weight: bold; }\n.cm-s-liquibyte span.cm-operator { color: #fff; }\n\n.cm-s-liquibyte span.cm-meta { color: #0f0; }\n.cm-s-liquibyte span.cm-qualifier { color: #fff700; font-weight: bold; }\n.cm-s-liquibyte span.cm-bracket { color: #cc7; }\n.cm-s-liquibyte span.cm-tag { color: #ff0; font-weight: bold; }\n.cm-s-liquibyte span.cm-attribute { color: #c080ff; font-weight: bold; }\n.cm-s-liquibyte span.cm-error { color: #f00; }\n\n.cm-s-liquibyte div.CodeMirror-selected { background-color: rgba(255, 0, 0, 0.25); }\n\n.cm-s-liquibyte span.cm-compilation { background-color: rgba(255, 255, 255, 0.12); }\n\n.cm-s-liquibyte .CodeMirror-activeline-background { background-color: rgba(0, 255, 0, 0.15); }\n\n/* Default styles for common addons */\n.cm-s-liquibyte .CodeMirror span.CodeMirror-matchingbracket { color: #0f0; font-weight: bold; }\n.cm-s-liquibyte .CodeMirror span.CodeMirror-nonmatchingbracket { color: #f00; font-weight: bold; }\n.CodeMirror-matchingtag { background-color: rgba(150, 255, 0, .3); }\n/* Scrollbars */\n/* Simple */\n.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div:hover, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div:hover {\n\tbackground-color: rgba(80, 80, 80, .7);\n}\n.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {\n\tbackground-color: rgba(80, 80, 80, .3);\n\tborder: 1px solid #404040;\n\tborder-radius: 5px;\n}\n.cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {\n\tborder-top: 1px solid #404040;\n\tborder-bottom: 1px solid #404040;\n}\n.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div {\n\tborder-left: 1px solid #404040;\n\tborder-right: 1px solid #404040;\n}\n.cm-s-liquibyte div.CodeMirror-simplescroll-vertical {\n\tbackground-color: #262626;\n}\n.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal {\n\tbackground-color: #262626;\n\tborder-top: 1px solid #404040;\n}\n/* Overlay */\n.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div, div.CodeMirror-overlayscroll-vertical div {\n\tbackground-color: #404040;\n\tborder-radius: 5px;\n}\n.cm-s-liquibyte div.CodeMirror-overlayscroll-vertical div {\n\tborder: 1px solid #404040;\n}\n.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div {\n\tborder: 1px solid #404040;\n}\n", - 'lucario': "/*\n Name: lucario\n Author: Raphael Amorim\n\n Original Lucario color scheme (https://github.com/raphamorim/lucario)\n*/\n\n.cm-s-lucario.CodeMirror, .cm-s-lucario .CodeMirror-gutters {\n background-color: #2b3e50 !important;\n color: #f8f8f2 !important;\n border: none;\n}\n.cm-s-lucario .CodeMirror-gutters { color: #2b3e50; }\n.cm-s-lucario .CodeMirror-cursor { border-left: solid thin #E6C845; }\n.cm-s-lucario .CodeMirror-linenumber { color: #f8f8f2; }\n.cm-s-lucario .CodeMirror-selected { background: #243443; }\n.cm-s-lucario .CodeMirror-line::selection, .cm-s-lucario .CodeMirror-line > span::selection, .cm-s-lucario .CodeMirror-line > span > span::selection { background: #243443; }\n.cm-s-lucario .CodeMirror-line::-moz-selection, .cm-s-lucario .CodeMirror-line > span::-moz-selection, .cm-s-lucario .CodeMirror-line > span > span::-moz-selection { background: #243443; }\n.cm-s-lucario span.cm-comment { color: #5c98cd; }\n.cm-s-lucario span.cm-string, .cm-s-lucario span.cm-string-2 { color: #E6DB74; }\n.cm-s-lucario span.cm-number { color: #ca94ff; }\n.cm-s-lucario span.cm-variable { color: #f8f8f2; }\n.cm-s-lucario span.cm-variable-2 { color: #f8f8f2; }\n.cm-s-lucario span.cm-def { color: #72C05D; }\n.cm-s-lucario span.cm-operator { color: #66D9EF; }\n.cm-s-lucario span.cm-keyword { color: #ff6541; }\n.cm-s-lucario span.cm-atom { color: #bd93f9; }\n.cm-s-lucario span.cm-meta { color: #f8f8f2; }\n.cm-s-lucario span.cm-tag { color: #ff6541; }\n.cm-s-lucario span.cm-attribute { color: #66D9EF; }\n.cm-s-lucario span.cm-qualifier { color: #72C05D; }\n.cm-s-lucario span.cm-property { color: #f8f8f2; }\n.cm-s-lucario span.cm-builtin { color: #72C05D; }\n.cm-s-lucario span.cm-variable-3, .cm-s-lucario span.cm-type { color: #ffb86c; }\n\n.cm-s-lucario .CodeMirror-activeline-background { background: #243443; }\n.cm-s-lucario .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'material-darker': "/*\n Name: material\n Author: Mattia Astorino (http://github.com/equinusocio)\n Website: https://material-theme.site/\n*/\n\n.cm-s-material-darker.CodeMirror {\n background-color: #212121;\n color: #EEFFFF;\n}\n\n.cm-s-material-darker .CodeMirror-gutters {\n background: #212121;\n color: #545454;\n border: none;\n}\n\n.cm-s-material-darker .CodeMirror-guttermarker,\n.cm-s-material-darker .CodeMirror-guttermarker-subtle,\n.cm-s-material-darker .CodeMirror-linenumber {\n color: #545454;\n}\n\n.cm-s-material-darker .CodeMirror-cursor {\n border-left: 1px solid #FFCC00;\n}\n\n.cm-s-material-darker div.CodeMirror-selected {\n background: rgba(97, 97, 97, 0.2);\n}\n\n.cm-s-material-darker.CodeMirror-focused div.CodeMirror-selected {\n background: rgba(97, 97, 97, 0.2);\n}\n\n.cm-s-material-darker .CodeMirror-line::selection,\n.cm-s-material-darker .CodeMirror-line>span::selection,\n.cm-s-material-darker .CodeMirror-line>span>span::selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material-darker .CodeMirror-line::-moz-selection,\n.cm-s-material-darker .CodeMirror-line>span::-moz-selection,\n.cm-s-material-darker .CodeMirror-line>span>span::-moz-selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material-darker .CodeMirror-activeline-background {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.cm-s-material-darker .cm-keyword {\n color: #C792EA;\n}\n\n.cm-s-material-darker .cm-operator {\n color: #89DDFF;\n}\n\n.cm-s-material-darker .cm-variable-2 {\n color: #EEFFFF;\n}\n\n.cm-s-material-darker .cm-variable-3,\n.cm-s-material-darker .cm-type {\n color: #f07178;\n}\n\n.cm-s-material-darker .cm-builtin {\n color: #FFCB6B;\n}\n\n.cm-s-material-darker .cm-atom {\n color: #F78C6C;\n}\n\n.cm-s-material-darker .cm-number {\n color: #FF5370;\n}\n\n.cm-s-material-darker .cm-def {\n color: #82AAFF;\n}\n\n.cm-s-material-darker .cm-string {\n color: #C3E88D;\n}\n\n.cm-s-material-darker .cm-string-2 {\n color: #f07178;\n}\n\n.cm-s-material-darker .cm-comment {\n color: #545454;\n}\n\n.cm-s-material-darker .cm-variable {\n color: #f07178;\n}\n\n.cm-s-material-darker .cm-tag {\n color: #FF5370;\n}\n\n.cm-s-material-darker .cm-meta {\n color: #FFCB6B;\n}\n\n.cm-s-material-darker .cm-attribute {\n color: #C792EA;\n}\n\n.cm-s-material-darker .cm-property {\n color: #C792EA;\n}\n\n.cm-s-material-darker .cm-qualifier {\n color: #DECB6B;\n}\n\n.cm-s-material-darker .cm-variable-3,\n.cm-s-material-darker .cm-type {\n color: #DECB6B;\n}\n\n\n.cm-s-material-darker .cm-error {\n color: rgba(255, 255, 255, 1.0);\n background-color: #FF5370;\n}\n\n.cm-s-material-darker .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}", - 'material-ocean': "/*\n Name: material\n Author: Mattia Astorino (http://github.com/equinusocio)\n Website: https://material-theme.site/\n*/\n\n.cm-s-material-ocean.CodeMirror {\n background-color: #0F111A;\n color: #8F93A2;\n}\n\n.cm-s-material-ocean .CodeMirror-gutters {\n background: #0F111A;\n color: #464B5D;\n border: none;\n}\n\n.cm-s-material-ocean .CodeMirror-guttermarker,\n.cm-s-material-ocean .CodeMirror-guttermarker-subtle,\n.cm-s-material-ocean .CodeMirror-linenumber {\n color: #464B5D;\n}\n\n.cm-s-material-ocean .CodeMirror-cursor {\n border-left: 1px solid #FFCC00;\n}\n.cm-s-material-ocean.cm-fat-cursor .CodeMirror-cursor {\n background-color: #a2a8a175 !important;\n}\n.cm-s-material-ocean .cm-animate-fat-cursor {\n background-color: #a2a8a175 !important;\n}\n\n.cm-s-material-ocean div.CodeMirror-selected {\n background: rgba(113, 124, 180, 0.2);\n}\n\n.cm-s-material-ocean.CodeMirror-focused div.CodeMirror-selected {\n background: rgba(113, 124, 180, 0.2);\n}\n\n.cm-s-material-ocean .CodeMirror-line::selection,\n.cm-s-material-ocean .CodeMirror-line>span::selection,\n.cm-s-material-ocean .CodeMirror-line>span>span::selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material-ocean .CodeMirror-line::-moz-selection,\n.cm-s-material-ocean .CodeMirror-line>span::-moz-selection,\n.cm-s-material-ocean .CodeMirror-line>span>span::-moz-selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material-ocean .CodeMirror-activeline-background {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.cm-s-material-ocean .cm-keyword {\n color: #C792EA;\n}\n\n.cm-s-material-ocean .cm-operator {\n color: #89DDFF;\n}\n\n.cm-s-material-ocean .cm-variable-2 {\n color: #EEFFFF;\n}\n\n.cm-s-material-ocean .cm-variable-3,\n.cm-s-material-ocean .cm-type {\n color: #f07178;\n}\n\n.cm-s-material-ocean .cm-builtin {\n color: #FFCB6B;\n}\n\n.cm-s-material-ocean .cm-atom {\n color: #F78C6C;\n}\n\n.cm-s-material-ocean .cm-number {\n color: #FF5370;\n}\n\n.cm-s-material-ocean .cm-def {\n color: #82AAFF;\n}\n\n.cm-s-material-ocean .cm-string {\n color: #C3E88D;\n}\n\n.cm-s-material-ocean .cm-string-2 {\n color: #f07178;\n}\n\n.cm-s-material-ocean .cm-comment {\n color: #464B5D;\n}\n\n.cm-s-material-ocean .cm-variable {\n color: #f07178;\n}\n\n.cm-s-material-ocean .cm-tag {\n color: #FF5370;\n}\n\n.cm-s-material-ocean .cm-meta {\n color: #FFCB6B;\n}\n\n.cm-s-material-ocean .cm-attribute {\n color: #C792EA;\n}\n\n.cm-s-material-ocean .cm-property {\n color: #C792EA;\n}\n\n.cm-s-material-ocean .cm-qualifier {\n color: #DECB6B;\n}\n\n.cm-s-material-ocean .cm-variable-3,\n.cm-s-material-ocean .cm-type {\n color: #DECB6B;\n}\n\n\n.cm-s-material-ocean .cm-error {\n color: rgba(255, 255, 255, 1.0);\n background-color: #FF5370;\n}\n\n.cm-s-material-ocean .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'material-palenight': "/*\n Name: material\n Author: Mattia Astorino (http://github.com/equinusocio)\n Website: https://material-theme.site/\n*/\n\n.cm-s-material-palenight.CodeMirror {\n background-color: #292D3E;\n color: #A6ACCD;\n}\n\n.cm-s-material-palenight .CodeMirror-gutters {\n background: #292D3E;\n color: #676E95;\n border: none;\n}\n\n.cm-s-material-palenight .CodeMirror-guttermarker,\n.cm-s-material-palenight .CodeMirror-guttermarker-subtle,\n.cm-s-material-palenight .CodeMirror-linenumber {\n color: #676E95;\n}\n\n.cm-s-material-palenight .CodeMirror-cursor {\n border-left: 1px solid #FFCC00;\n}\n.cm-s-material-palenight.cm-fat-cursor .CodeMirror-cursor {\n background-color: #607c8b80 !important;\n}\n.cm-s-material-palenight .cm-animate-fat-cursor {\n background-color: #607c8b80 !important;\n}\n\n.cm-s-material-palenight div.CodeMirror-selected {\n background: rgba(113, 124, 180, 0.2);\n}\n\n.cm-s-material-palenight.CodeMirror-focused div.CodeMirror-selected {\n background: rgba(113, 124, 180, 0.2);\n}\n\n.cm-s-material-palenight .CodeMirror-line::selection,\n.cm-s-material-palenight .CodeMirror-line>span::selection,\n.cm-s-material-palenight .CodeMirror-line>span>span::selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material-palenight .CodeMirror-line::-moz-selection,\n.cm-s-material-palenight .CodeMirror-line>span::-moz-selection,\n.cm-s-material-palenight .CodeMirror-line>span>span::-moz-selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material-palenight .CodeMirror-activeline-background {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.cm-s-material-palenight .cm-keyword {\n color: #C792EA;\n}\n\n.cm-s-material-palenight .cm-operator {\n color: #89DDFF;\n}\n\n.cm-s-material-palenight .cm-variable-2 {\n color: #EEFFFF;\n}\n\n.cm-s-material-palenight .cm-variable-3,\n.cm-s-material-palenight .cm-type {\n color: #f07178;\n}\n\n.cm-s-material-palenight .cm-builtin {\n color: #FFCB6B;\n}\n\n.cm-s-material-palenight .cm-atom {\n color: #F78C6C;\n}\n\n.cm-s-material-palenight .cm-number {\n color: #FF5370;\n}\n\n.cm-s-material-palenight .cm-def {\n color: #82AAFF;\n}\n\n.cm-s-material-palenight .cm-string {\n color: #C3E88D;\n}\n\n.cm-s-material-palenight .cm-string-2 {\n color: #f07178;\n}\n\n.cm-s-material-palenight .cm-comment {\n color: #676E95;\n}\n\n.cm-s-material-palenight .cm-variable {\n color: #f07178;\n}\n\n.cm-s-material-palenight .cm-tag {\n color: #FF5370;\n}\n\n.cm-s-material-palenight .cm-meta {\n color: #FFCB6B;\n}\n\n.cm-s-material-palenight .cm-attribute {\n color: #C792EA;\n}\n\n.cm-s-material-palenight .cm-property {\n color: #C792EA;\n}\n\n.cm-s-material-palenight .cm-qualifier {\n color: #DECB6B;\n}\n\n.cm-s-material-palenight .cm-variable-3,\n.cm-s-material-palenight .cm-type {\n color: #DECB6B;\n}\n\n\n.cm-s-material-palenight .cm-error {\n color: rgba(255, 255, 255, 1.0);\n background-color: #FF5370;\n}\n\n.cm-s-material-palenight .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'material': "/*\n Name: material\n Author: Mattia Astorino (http://github.com/equinusocio)\n Website: https://material-theme.site/\n*/\n\n.cm-s-material.CodeMirror {\n background-color: #263238;\n color: #EEFFFF;\n}\n\n.cm-s-material .CodeMirror-gutters {\n background: #263238;\n color: #546E7A;\n border: none;\n}\n\n.cm-s-material .CodeMirror-guttermarker,\n.cm-s-material .CodeMirror-guttermarker-subtle,\n.cm-s-material .CodeMirror-linenumber {\n color: #546E7A;\n}\n\n.cm-s-material .CodeMirror-cursor {\n border-left: 1px solid #FFCC00;\n}\n.cm-s-material.cm-fat-cursor .CodeMirror-cursor {\n background-color: #5d6d5c80 !important;\n}\n.cm-s-material .cm-animate-fat-cursor {\n background-color: #5d6d5c80 !important;\n}\n\n.cm-s-material div.CodeMirror-selected {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material.CodeMirror-focused div.CodeMirror-selected {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material .CodeMirror-line::selection,\n.cm-s-material .CodeMirror-line>span::selection,\n.cm-s-material .CodeMirror-line>span>span::selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material .CodeMirror-line::-moz-selection,\n.cm-s-material .CodeMirror-line>span::-moz-selection,\n.cm-s-material .CodeMirror-line>span>span::-moz-selection {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-material .CodeMirror-activeline-background {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.cm-s-material .cm-keyword {\n color: #C792EA;\n}\n\n.cm-s-material .cm-operator {\n color: #89DDFF;\n}\n\n.cm-s-material .cm-variable-2 {\n color: #EEFFFF;\n}\n\n.cm-s-material .cm-variable-3,\n.cm-s-material .cm-type {\n color: #f07178;\n}\n\n.cm-s-material .cm-builtin {\n color: #FFCB6B;\n}\n\n.cm-s-material .cm-atom {\n color: #F78C6C;\n}\n\n.cm-s-material .cm-number {\n color: #FF5370;\n}\n\n.cm-s-material .cm-def {\n color: #82AAFF;\n}\n\n.cm-s-material .cm-string {\n color: #C3E88D;\n}\n\n.cm-s-material .cm-string-2 {\n color: #f07178;\n}\n\n.cm-s-material .cm-comment {\n color: #546E7A;\n}\n\n.cm-s-material .cm-variable {\n color: #f07178;\n}\n\n.cm-s-material .cm-tag {\n color: #FF5370;\n}\n\n.cm-s-material .cm-meta {\n color: #FFCB6B;\n}\n\n.cm-s-material .cm-attribute {\n color: #C792EA;\n}\n\n.cm-s-material .cm-property {\n color: #C792EA;\n}\n\n.cm-s-material .cm-qualifier {\n color: #DECB6B;\n}\n\n.cm-s-material .cm-variable-3,\n.cm-s-material .cm-type {\n color: #DECB6B;\n}\n\n\n.cm-s-material .cm-error {\n color: rgba(255, 255, 255, 1.0);\n background-color: #FF5370;\n}\n\n.cm-s-material .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'mbo': "/****************************************************************/\n/* Based on mbonaci's Brackets mbo theme */\n/* https://github.com/mbonaci/global/blob/master/Mbo.tmTheme */\n/* Create your own: http://tmtheme-editor.herokuapp.com */\n/****************************************************************/\n\n.cm-s-mbo.CodeMirror { background: #2c2c2c; color: #ffffec; }\n.cm-s-mbo div.CodeMirror-selected { background: #716C62; }\n.cm-s-mbo .CodeMirror-line::selection, .cm-s-mbo .CodeMirror-line > span::selection, .cm-s-mbo .CodeMirror-line > span > span::selection { background: rgba(113, 108, 98, .99); }\n.cm-s-mbo .CodeMirror-line::-moz-selection, .cm-s-mbo .CodeMirror-line > span::-moz-selection, .cm-s-mbo .CodeMirror-line > span > span::-moz-selection { background: rgba(113, 108, 98, .99); }\n.cm-s-mbo .CodeMirror-gutters { background: #4e4e4e; border-right: 0px; }\n.cm-s-mbo .CodeMirror-guttermarker { color: white; }\n.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; }\n.cm-s-mbo .CodeMirror-linenumber { color: #dadada; }\n.cm-s-mbo .CodeMirror-cursor { border-left: 1px solid #ffffec; }\n\n.cm-s-mbo span.cm-comment { color: #95958a; }\n.cm-s-mbo span.cm-atom { color: #00a8c6; }\n.cm-s-mbo span.cm-number { color: #00a8c6; }\n\n.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute { color: #9ddfe9; }\n.cm-s-mbo span.cm-keyword { color: #ffb928; }\n.cm-s-mbo span.cm-string { color: #ffcf6c; }\n.cm-s-mbo span.cm-string.cm-property { color: #ffffec; }\n\n.cm-s-mbo span.cm-variable { color: #ffffec; }\n.cm-s-mbo span.cm-variable-2 { color: #00a8c6; }\n.cm-s-mbo span.cm-def { color: #ffffec; }\n.cm-s-mbo span.cm-bracket { color: #fffffc; font-weight: bold; }\n.cm-s-mbo span.cm-tag { color: #9ddfe9; }\n.cm-s-mbo span.cm-link { color: #f54b07; }\n.cm-s-mbo span.cm-error { border-bottom: #636363; color: #ffffec; }\n.cm-s-mbo span.cm-qualifier { color: #ffffec; }\n\n.cm-s-mbo .CodeMirror-activeline-background { background: #494b41; }\n.cm-s-mbo .CodeMirror-matchingbracket { color: #ffb928 !important; }\n.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); }\n", - 'mdn-like': "/*\n MDN-LIKE Theme - Mozilla\n Ported to CodeMirror by Peter Kroon \n Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues\n GitHub: @peterkroon\n\n The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation\n\n*/\n.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; }\n.cm-s-mdn-like div.CodeMirror-selected { background: #cfc; }\n.cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; }\n.cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; }\n\n.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; }\n.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; }\n.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; }\n\n.cm-s-mdn-like .cm-keyword { color: #6262FF; }\n.cm-s-mdn-like .cm-atom { color: #F90; }\n.cm-s-mdn-like .cm-number { color: #ca7841; }\n.cm-s-mdn-like .cm-def { color: #8DA6CE; }\n.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; }\n.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; }\n\n.cm-s-mdn-like .cm-variable { color: #07a; }\n.cm-s-mdn-like .cm-property { color: #905; }\n.cm-s-mdn-like .cm-qualifier { color: #690; }\n\n.cm-s-mdn-like .cm-operator { color: #cda869; }\n.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; }\n.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; }\n.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/\n.cm-s-mdn-like .cm-meta { color: #000; } /*?*/\n.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/\n.cm-s-mdn-like .cm-tag { color: #997643; }\n.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/\n.cm-s-mdn-like .cm-header { color: #FF6400; }\n.cm-s-mdn-like .cm-hr { color: #AEAEAE; }\n.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; }\n.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; }\n\ndiv.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; }\ndiv.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; }\n\n.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); }\n", - 'midnight': "/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */\n\n/**/\n.cm-s-midnight .CodeMirror-activeline-background { background: #253540; }\n\n.cm-s-midnight.CodeMirror {\n background: #0F192A;\n color: #D1EDFF;\n}\n\n.cm-s-midnight div.CodeMirror-selected { background: #314D67; }\n.cm-s-midnight .CodeMirror-line::selection, .cm-s-midnight .CodeMirror-line > span::selection, .cm-s-midnight .CodeMirror-line > span > span::selection { background: rgba(49, 77, 103, .99); }\n.cm-s-midnight .CodeMirror-line::-moz-selection, .cm-s-midnight .CodeMirror-line > span::-moz-selection, .cm-s-midnight .CodeMirror-line > span > span::-moz-selection { background: rgba(49, 77, 103, .99); }\n.cm-s-midnight .CodeMirror-gutters { background: #0F192A; border-right: 1px solid; }\n.cm-s-midnight .CodeMirror-guttermarker { color: white; }\n.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-midnight .CodeMirror-linenumber { color: #D0D0D0; }\n.cm-s-midnight .CodeMirror-cursor { border-left: 1px solid #F8F8F0; }\n\n.cm-s-midnight span.cm-comment { color: #428BDD; }\n.cm-s-midnight span.cm-atom { color: #AE81FF; }\n.cm-s-midnight span.cm-number { color: #D1EDFF; }\n\n.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute { color: #A6E22E; }\n.cm-s-midnight span.cm-keyword { color: #E83737; }\n.cm-s-midnight span.cm-string { color: #1DC116; }\n\n.cm-s-midnight span.cm-variable { color: #FFAA3E; }\n.cm-s-midnight span.cm-variable-2 { color: #FFAA3E; }\n.cm-s-midnight span.cm-def { color: #4DD; }\n.cm-s-midnight span.cm-bracket { color: #D1EDFF; }\n.cm-s-midnight span.cm-tag { color: #449; }\n.cm-s-midnight span.cm-link { color: #AE81FF; }\n.cm-s-midnight span.cm-error { background: #F92672; color: #F8F8F0; }\n\n.cm-s-midnight .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'monokai': "/* Based on Sublime Text's Monokai theme */\n\n.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }\n.cm-s-monokai div.CodeMirror-selected { background: #49483E; }\n.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }\n.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }\n.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }\n.cm-s-monokai .CodeMirror-guttermarker { color: white; }\n.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }\n\n.cm-s-monokai span.cm-comment { color: #75715e; }\n.cm-s-monokai span.cm-atom { color: #ae81ff; }\n.cm-s-monokai span.cm-number { color: #ae81ff; }\n\n.cm-s-monokai span.cm-comment.cm-attribute { color: #97b757; }\n.cm-s-monokai span.cm-comment.cm-def { color: #bc9262; }\n.cm-s-monokai span.cm-comment.cm-tag { color: #bc6283; }\n.cm-s-monokai span.cm-comment.cm-type { color: #5998a6; }\n\n.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }\n.cm-s-monokai span.cm-keyword { color: #f92672; }\n.cm-s-monokai span.cm-builtin { color: #66d9ef; }\n.cm-s-monokai span.cm-string { color: #e6db74; }\n\n.cm-s-monokai span.cm-variable { color: #f8f8f2; }\n.cm-s-monokai span.cm-variable-2 { color: #9effff; }\n.cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; }\n.cm-s-monokai span.cm-def { color: #fd971f; }\n.cm-s-monokai span.cm-bracket { color: #f8f8f2; }\n.cm-s-monokai span.cm-tag { color: #f92672; }\n.cm-s-monokai span.cm-header { color: #ae81ff; }\n.cm-s-monokai span.cm-link { color: #ae81ff; }\n.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }\n\n.cm-s-monokai .CodeMirror-activeline-background { background: #373831; }\n.cm-s-monokai .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'moxer': "/*\n Name: Moxer Theme\n Author: Mattia Astorino (http://github.com/equinusocio)\n Website: https://github.com/moxer-theme/moxer-code\n*/\n\n.cm-s-moxer.CodeMirror {\n background-color: #090A0F;\n color: #8E95B4;\n line-height: 1.8;\n}\n\n.cm-s-moxer .CodeMirror-gutters {\n background: #090A0F;\n color: #35394B;\n border: none;\n}\n\n.cm-s-moxer .CodeMirror-guttermarker,\n.cm-s-moxer .CodeMirror-guttermarker-subtle,\n.cm-s-moxer .CodeMirror-linenumber {\n color: #35394B;\n}\n\n\n.cm-s-moxer .CodeMirror-cursor {\n border-left: 1px solid #FFCC00;\n}\n\n.cm-s-moxer div.CodeMirror-selected {\n background: rgba(128, 203, 196, 0.2);\n}\n\n.cm-s-moxer.CodeMirror-focused div.CodeMirror-selected {\n background: #212431;\n}\n\n.cm-s-moxer .CodeMirror-line::selection,\n.cm-s-moxer .CodeMirror-line>span::selection,\n.cm-s-moxer .CodeMirror-line>span>span::selection {\n background: #212431;\n}\n\n.cm-s-moxer .CodeMirror-line::-moz-selection,\n.cm-s-moxer .CodeMirror-line>span::-moz-selection,\n.cm-s-moxer .CodeMirror-line>span>span::-moz-selection {\n background: #212431;\n}\n\n.cm-s-moxer .CodeMirror-activeline-background,\n.cm-s-moxer .CodeMirror-activeline-gutter .CodeMirror-linenumber {\n background: rgba(33, 36, 49, 0.5);\n}\n\n.cm-s-moxer .cm-keyword {\n color: #D46C6C;\n}\n\n.cm-s-moxer .cm-operator {\n color: #D46C6C;\n}\n\n.cm-s-moxer .cm-variable-2 {\n color: #81C5DA;\n}\n\n\n.cm-s-moxer .cm-variable-3,\n.cm-s-moxer .cm-type {\n color: #f07178;\n}\n\n.cm-s-moxer .cm-builtin {\n color: #FFCB6B;\n}\n\n.cm-s-moxer .cm-atom {\n color: #A99BE2;\n}\n\n.cm-s-moxer .cm-number {\n color: #7CA4C0;\n}\n\n.cm-s-moxer .cm-def {\n color: #F5DFA5;\n}\n\n.cm-s-moxer .CodeMirror-line .cm-def ~ .cm-def {\n color: #81C5DA;\n}\n\n.cm-s-moxer .cm-string {\n color: #B2E4AE;\n}\n\n.cm-s-moxer .cm-string-2 {\n color: #f07178;\n}\n\n.cm-s-moxer .cm-comment {\n color: #3F445A;\n}\n\n.cm-s-moxer .cm-variable {\n color: #8E95B4;\n}\n\n.cm-s-moxer .cm-tag {\n color: #FF5370;\n}\n\n.cm-s-moxer .cm-meta {\n color: #FFCB6B;\n}\n\n.cm-s-moxer .cm-attribute {\n color: #C792EA;\n}\n\n.cm-s-moxer .cm-property {\n color: #81C5DA;\n}\n\n.cm-s-moxer .cm-qualifier {\n color: #DECB6B;\n}\n\n.cm-s-moxer .cm-variable-3,\n.cm-s-moxer .cm-type {\n color: #DECB6B;\n}\n\n\n.cm-s-moxer .cm-error {\n color: rgba(255, 255, 255, 1.0);\n background-color: #FF5370;\n}\n\n.cm-s-moxer .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}", - 'neat': ".cm-s-neat span.cm-comment { color: #a86; }\n.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }\n.cm-s-neat span.cm-string { color: #a22; }\n.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }\n.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }\n.cm-s-neat span.cm-variable { color: black; }\n.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }\n.cm-s-neat span.cm-meta { color: #555; }\n.cm-s-neat span.cm-link { color: #3a3; }\n\n.cm-s-neat .CodeMirror-activeline-background { background: #e8f2ff; }\n.cm-s-neat .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\n", - 'neo': "/* neo theme for codemirror */\n\n/* Color scheme */\n\n.cm-s-neo.CodeMirror {\n background-color:#ffffff;\n color:#2e383c;\n line-height:1.4375;\n}\n.cm-s-neo .cm-comment { color:#75787b; }\n.cm-s-neo .cm-keyword, .cm-s-neo .cm-property { color:#1d75b3; }\n.cm-s-neo .cm-atom,.cm-s-neo .cm-number { color:#75438a; }\n.cm-s-neo .cm-node,.cm-s-neo .cm-tag { color:#9c3328; }\n.cm-s-neo .cm-string { color:#b35e14; }\n.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier { color:#047d65; }\n\n\n/* Editor styling */\n\n.cm-s-neo pre {\n padding:0;\n}\n\n.cm-s-neo .CodeMirror-gutters {\n border:none;\n border-right:10px solid transparent;\n background-color:transparent;\n}\n\n.cm-s-neo .CodeMirror-linenumber {\n padding:0;\n color:#e0e2e5;\n}\n\n.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; }\n.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; }\n\n.cm-s-neo .CodeMirror-cursor {\n width: auto;\n border: 0;\n background: rgba(155,157,162,0.37);\n z-index: 1;\n}\n", - 'night': "/* Loosely based on the Midnight Textmate theme */\n\n.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; }\n.cm-s-night div.CodeMirror-selected { background: #447; }\n.cm-s-night .CodeMirror-line::selection, .cm-s-night .CodeMirror-line > span::selection, .cm-s-night .CodeMirror-line > span > span::selection { background: rgba(68, 68, 119, .99); }\n.cm-s-night .CodeMirror-line::-moz-selection, .cm-s-night .CodeMirror-line > span::-moz-selection, .cm-s-night .CodeMirror-line > span > span::-moz-selection { background: rgba(68, 68, 119, .99); }\n.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\n.cm-s-night .CodeMirror-guttermarker { color: white; }\n.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; }\n.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; }\n.cm-s-night .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-night span.cm-comment { color: #8900d1; }\n.cm-s-night span.cm-atom { color: #845dc4; }\n.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }\n.cm-s-night span.cm-keyword { color: #599eff; }\n.cm-s-night span.cm-string { color: #37f14a; }\n.cm-s-night span.cm-meta { color: #7678e2; }\n.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }\n.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def, .cm-s-night span.cm-type { color: white; }\n.cm-s-night span.cm-bracket { color: #8da6ce; }\n.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }\n.cm-s-night span.cm-link { color: #845dc4; }\n.cm-s-night span.cm-error { color: #9d1e15; }\n\n.cm-s-night .CodeMirror-activeline-background { background: #1C005A; }\n.cm-s-night .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\n", - 'nord': "/* Based on arcticicestudio's Nord theme */\n/* https://github.com/arcticicestudio/nord */\n\n.cm-s-nord.CodeMirror { background: #2e3440; color: #d8dee9; }\n.cm-s-nord div.CodeMirror-selected { background: #434c5e; }\n.cm-s-nord .CodeMirror-line::selection, .cm-s-nord .CodeMirror-line > span::selection, .cm-s-nord .CodeMirror-line > span > span::selection { background: #3b4252; }\n.cm-s-nord .CodeMirror-line::-moz-selection, .cm-s-nord .CodeMirror-line > span::-moz-selection, .cm-s-nord .CodeMirror-line > span > span::-moz-selection { background: #3b4252; }\n.cm-s-nord .CodeMirror-gutters { background: #2e3440; border-right: 0px; }\n.cm-s-nord .CodeMirror-guttermarker { color: #4c566a; }\n.cm-s-nord .CodeMirror-guttermarker-subtle { color: #4c566a; }\n.cm-s-nord .CodeMirror-linenumber { color: #4c566a; }\n.cm-s-nord .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }\n\n.cm-s-nord span.cm-comment { color: #4c566a; }\n.cm-s-nord span.cm-atom { color: #b48ead; }\n.cm-s-nord span.cm-number { color: #b48ead; }\n\n.cm-s-nord span.cm-comment.cm-attribute { color: #97b757; }\n.cm-s-nord span.cm-comment.cm-def { color: #bc9262; }\n.cm-s-nord span.cm-comment.cm-tag { color: #bc6283; }\n.cm-s-nord span.cm-comment.cm-type { color: #5998a6; }\n\n.cm-s-nord span.cm-property, .cm-s-nord span.cm-attribute { color: #8FBCBB; }\n.cm-s-nord span.cm-keyword { color: #81A1C1; }\n.cm-s-nord span.cm-builtin { color: #81A1C1; }\n.cm-s-nord span.cm-string { color: #A3BE8C; }\n\n.cm-s-nord span.cm-variable { color: #d8dee9; }\n.cm-s-nord span.cm-variable-2 { color: #d8dee9; }\n.cm-s-nord span.cm-variable-3, .cm-s-nord span.cm-type { color: #d8dee9; }\n.cm-s-nord span.cm-def { color: #8FBCBB; }\n.cm-s-nord span.cm-bracket { color: #81A1C1; }\n.cm-s-nord span.cm-tag { color: #bf616a; }\n.cm-s-nord span.cm-header { color: #b48ead; }\n.cm-s-nord span.cm-link { color: #b48ead; }\n.cm-s-nord span.cm-error { background: #bf616a; color: #f8f8f0; }\n\n.cm-s-nord .CodeMirror-activeline-background { background: #3b4252; }\n.cm-s-nord .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'oceanic-next': "/*\n\n Name: oceanic-next\n Author: Filype Pereira (https://github.com/fpereira1)\n\n Original oceanic-next color scheme by Dmitri Voronianski (https://github.com/voronianski/oceanic-next-color-scheme)\n\n*/\n\n.cm-s-oceanic-next.CodeMirror { background: #304148; color: #f8f8f2; }\n.cm-s-oceanic-next div.CodeMirror-selected { background: rgba(101, 115, 126, 0.33); }\n.cm-s-oceanic-next .CodeMirror-line::selection, .cm-s-oceanic-next .CodeMirror-line > span::selection, .cm-s-oceanic-next .CodeMirror-line > span > span::selection { background: rgba(101, 115, 126, 0.33); }\n.cm-s-oceanic-next .CodeMirror-line::-moz-selection, .cm-s-oceanic-next .CodeMirror-line > span::-moz-selection, .cm-s-oceanic-next .CodeMirror-line > span > span::-moz-selection { background: rgba(101, 115, 126, 0.33); }\n.cm-s-oceanic-next .CodeMirror-gutters { background: #304148; border-right: 10px; }\n.cm-s-oceanic-next .CodeMirror-guttermarker { color: white; }\n.cm-s-oceanic-next .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-oceanic-next .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-oceanic-next .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }\n.cm-s-oceanic-next.cm-fat-cursor .CodeMirror-cursor { background-color: #a2a8a175 !important; }\n.cm-s-oceanic-next .cm-animate-fat-cursor { background-color: #a2a8a175 !important; }\n\n.cm-s-oceanic-next span.cm-comment { color: #65737E; }\n.cm-s-oceanic-next span.cm-atom { color: #C594C5; }\n.cm-s-oceanic-next span.cm-number { color: #F99157; }\n\n.cm-s-oceanic-next span.cm-property { color: #99C794; }\n.cm-s-oceanic-next span.cm-attribute,\n.cm-s-oceanic-next span.cm-keyword { color: #C594C5; }\n.cm-s-oceanic-next span.cm-builtin { color: #66d9ef; }\n.cm-s-oceanic-next span.cm-string { color: #99C794; }\n\n.cm-s-oceanic-next span.cm-variable,\n.cm-s-oceanic-next span.cm-variable-2,\n.cm-s-oceanic-next span.cm-variable-3 { color: #f8f8f2; }\n.cm-s-oceanic-next span.cm-def { color: #6699CC; }\n.cm-s-oceanic-next span.cm-bracket { color: #5FB3B3; }\n.cm-s-oceanic-next span.cm-tag { color: #C594C5; }\n.cm-s-oceanic-next span.cm-header { color: #C594C5; }\n.cm-s-oceanic-next span.cm-link { color: #C594C5; }\n.cm-s-oceanic-next span.cm-error { background: #C594C5; color: #f8f8f0; }\n\n.cm-s-oceanic-next .CodeMirror-activeline-background { background: rgba(101, 115, 126, 0.33); }\n.cm-s-oceanic-next .CodeMirror-matchingbracket {\n text-decoration: underline;\n color: white !important;\n}\n", - 'panda-syntax': "/*\n\tName: Panda Syntax\n\tAuthor: Siamak Mokhtari (http://github.com/siamak/)\n\tCodeMirror template by Siamak Mokhtari (https://github.com/siamak/atom-panda-syntax)\n*/\n.cm-s-panda-syntax {\n\tbackground: #292A2B;\n\tcolor: #E6E6E6;\n\tline-height: 1.5;\n\tfont-family: 'Operator Mono', 'Source Code Pro', Menlo, Monaco, Consolas, Courier New, monospace;\n}\n.cm-s-panda-syntax .CodeMirror-cursor { border-color: #ff2c6d; }\n.cm-s-panda-syntax .CodeMirror-activeline-background {\n\tbackground: rgba(99, 123, 156, 0.1);\n}\n.cm-s-panda-syntax .CodeMirror-selected {\n\tbackground: #FFF;\n}\n.cm-s-panda-syntax .cm-comment {\n\tfont-style: italic;\n\tcolor: #676B79;\n}\n.cm-s-panda-syntax .cm-operator {\n\tcolor: #f3f3f3;\n}\n.cm-s-panda-syntax .cm-string {\n\tcolor: #19F9D8;\n}\n.cm-s-panda-syntax .cm-string-2 {\n color: #FFB86C;\n}\n\n.cm-s-panda-syntax .cm-tag {\n\tcolor: #ff2c6d;\n}\n.cm-s-panda-syntax .cm-meta {\n\tcolor: #b084eb;\n}\n\n.cm-s-panda-syntax .cm-number {\n\tcolor: #FFB86C;\n}\n.cm-s-panda-syntax .cm-atom {\n\tcolor: #ff2c6d;\n}\n.cm-s-panda-syntax .cm-keyword {\n\tcolor: #FF75B5;\n}\n.cm-s-panda-syntax .cm-variable {\n\tcolor: #ffb86c;\n}\n.cm-s-panda-syntax .cm-variable-2 {\n\tcolor: #ff9ac1;\n}\n.cm-s-panda-syntax .cm-variable-3, .cm-s-panda-syntax .cm-type {\n\tcolor: #ff9ac1;\n}\n\n.cm-s-panda-syntax .cm-def {\n\tcolor: #e6e6e6;\n}\n.cm-s-panda-syntax .cm-property {\n\tcolor: #f3f3f3;\n}\n.cm-s-panda-syntax .cm-unit {\n color: #ffb86c;\n}\n\n.cm-s-panda-syntax .cm-attribute {\n color: #ffb86c;\n}\n\n.cm-s-panda-syntax .CodeMirror-matchingbracket {\n border-bottom: 1px dotted #19F9D8;\n padding-bottom: 2px;\n color: #e6e6e6;\n}\n.cm-s-panda-syntax .CodeMirror-gutters {\n background: #292a2b;\n border-right-color: rgba(255, 255, 255, 0.1);\n}\n.cm-s-panda-syntax .CodeMirror-linenumber {\n color: #e6e6e6;\n opacity: 0.6;\n}\n", - 'paraiso-dark': "/*\n\n Name: Paraíso (Dark)\n Author: Jan T. Sott\n\n Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)\n Inspired by the art of Rubens LP (http://www.rubenslp.com.br)\n\n*/\n\n.cm-s-paraiso-dark.CodeMirror { background: #2f1e2e; color: #b9b6b0; }\n.cm-s-paraiso-dark div.CodeMirror-selected { background: #41323f; }\n.cm-s-paraiso-dark .CodeMirror-line::selection, .cm-s-paraiso-dark .CodeMirror-line > span::selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::selection { background: rgba(65, 50, 63, .99); }\n.cm-s-paraiso-dark .CodeMirror-line::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(65, 50, 63, .99); }\n.cm-s-paraiso-dark .CodeMirror-gutters { background: #2f1e2e; border-right: 0px; }\n.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; }\n.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; }\n.cm-s-paraiso-dark .CodeMirror-linenumber { color: #776e71; }\n.cm-s-paraiso-dark .CodeMirror-cursor { border-left: 1px solid #8d8687; }\n\n.cm-s-paraiso-dark span.cm-comment { color: #e96ba8; }\n.cm-s-paraiso-dark span.cm-atom { color: #815ba4; }\n.cm-s-paraiso-dark span.cm-number { color: #815ba4; }\n\n.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute { color: #48b685; }\n.cm-s-paraiso-dark span.cm-keyword { color: #ef6155; }\n.cm-s-paraiso-dark span.cm-string { color: #fec418; }\n\n.cm-s-paraiso-dark span.cm-variable { color: #48b685; }\n.cm-s-paraiso-dark span.cm-variable-2 { color: #06b6ef; }\n.cm-s-paraiso-dark span.cm-def { color: #f99b15; }\n.cm-s-paraiso-dark span.cm-bracket { color: #b9b6b0; }\n.cm-s-paraiso-dark span.cm-tag { color: #ef6155; }\n.cm-s-paraiso-dark span.cm-link { color: #815ba4; }\n.cm-s-paraiso-dark span.cm-error { background: #ef6155; color: #8d8687; }\n\n.cm-s-paraiso-dark .CodeMirror-activeline-background { background: #4D344A; }\n.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'paraiso-light': "/*\n\n Name: Paraíso (Light)\n Author: Jan T. Sott\n\n Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)\n Inspired by the art of Rubens LP (http://www.rubenslp.com.br)\n\n*/\n\n.cm-s-paraiso-light.CodeMirror { background: #e7e9db; color: #41323f; }\n.cm-s-paraiso-light div.CodeMirror-selected { background: #b9b6b0; }\n.cm-s-paraiso-light .CodeMirror-line::selection, .cm-s-paraiso-light .CodeMirror-line > span::selection, .cm-s-paraiso-light .CodeMirror-line > span > span::selection { background: #b9b6b0; }\n.cm-s-paraiso-light .CodeMirror-line::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span > span::-moz-selection { background: #b9b6b0; }\n.cm-s-paraiso-light .CodeMirror-gutters { background: #e7e9db; border-right: 0px; }\n.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; }\n.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; }\n.cm-s-paraiso-light .CodeMirror-linenumber { color: #8d8687; }\n.cm-s-paraiso-light .CodeMirror-cursor { border-left: 1px solid #776e71; }\n\n.cm-s-paraiso-light span.cm-comment { color: #e96ba8; }\n.cm-s-paraiso-light span.cm-atom { color: #815ba4; }\n.cm-s-paraiso-light span.cm-number { color: #815ba4; }\n\n.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute { color: #48b685; }\n.cm-s-paraiso-light span.cm-keyword { color: #ef6155; }\n.cm-s-paraiso-light span.cm-string { color: #fec418; }\n\n.cm-s-paraiso-light span.cm-variable { color: #48b685; }\n.cm-s-paraiso-light span.cm-variable-2 { color: #06b6ef; }\n.cm-s-paraiso-light span.cm-def { color: #f99b15; }\n.cm-s-paraiso-light span.cm-bracket { color: #41323f; }\n.cm-s-paraiso-light span.cm-tag { color: #ef6155; }\n.cm-s-paraiso-light span.cm-link { color: #815ba4; }\n.cm-s-paraiso-light span.cm-error { background: #ef6155; color: #776e71; }\n\n.cm-s-paraiso-light .CodeMirror-activeline-background { background: #CFD1C4; }\n.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'pastel-on-dark': "/**\n * Pastel On Dark theme ported from ACE editor\n * @license MIT\n * @copyright AtomicPages LLC 2014\n * @author Dennis Thompson, AtomicPages LLC\n * @version 1.1\n * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme\n */\n\n.cm-s-pastel-on-dark.CodeMirror {\n\tbackground: #2c2827;\n\tcolor: #8F938F;\n\tline-height: 1.5;\n}\n.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2); }\n.cm-s-pastel-on-dark .CodeMirror-line::selection, .cm-s-pastel-on-dark .CodeMirror-line > span::selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::selection { background: rgba(221,240,255,0.2); }\n.cm-s-pastel-on-dark .CodeMirror-line::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(221,240,255,0.2); }\n\n.cm-s-pastel-on-dark .CodeMirror-gutters {\n\tbackground: #34302f;\n\tborder-right: 0px;\n\tpadding: 0 3px;\n}\n.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; }\n.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; }\n.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }\n.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }\n.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }\n.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }\n.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }\n.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }\n.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }\n.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }\n.cm-s-pastel-on-dark span.cm-string { color: #66A968; }\n.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }\n.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }\n.cm-s-pastel-on-dark span.cm-variable-3, .cm-s-pastel-on-dark span.cm-type { color: #DE8E30; }\n.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }\n.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }\n.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }\n.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }\n.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }\n.cm-s-pastel-on-dark span.cm-error {\n\tbackground: #757aD8;\n\tcolor: #f8f8f0;\n}\n.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031); }\n.cm-s-pastel-on-dark .CodeMirror-matchingbracket {\n\tborder: 1px solid rgba(255,255,255,0.25);\n\tcolor: #8F938F !important;\n\tmargin: -1px -1px 0 -1px;\n}\n", - 'railscasts': "/*\n\n Name: Railscasts\n Author: Ryan Bates (http://railscasts.com)\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-railscasts.CodeMirror {background: #2b2b2b; color: #f4f1ed;}\n.cm-s-railscasts div.CodeMirror-selected {background: #272935 !important;}\n.cm-s-railscasts .CodeMirror-gutters {background: #2b2b2b; border-right: 0px;}\n.cm-s-railscasts .CodeMirror-linenumber {color: #5a647e;}\n.cm-s-railscasts .CodeMirror-cursor {border-left: 1px solid #d4cfc9 !important;}\n\n.cm-s-railscasts span.cm-comment {color: #bc9458;}\n.cm-s-railscasts span.cm-atom {color: #b6b3eb;}\n.cm-s-railscasts span.cm-number {color: #b6b3eb;}\n\n.cm-s-railscasts span.cm-property, .cm-s-railscasts span.cm-attribute {color: #a5c261;}\n.cm-s-railscasts span.cm-keyword {color: #da4939;}\n.cm-s-railscasts span.cm-string {color: #ffc66d;}\n\n.cm-s-railscasts span.cm-variable {color: #a5c261;}\n.cm-s-railscasts span.cm-variable-2 {color: #6d9cbe;}\n.cm-s-railscasts span.cm-def {color: #cc7833;}\n.cm-s-railscasts span.cm-error {background: #da4939; color: #d4cfc9;}\n.cm-s-railscasts span.cm-bracket {color: #f4f1ed;}\n.cm-s-railscasts span.cm-tag {color: #da4939;}\n.cm-s-railscasts span.cm-link {color: #b6b3eb;}\n\n.cm-s-railscasts .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n.cm-s-railscasts .CodeMirror-activeline-background { background: #303040; }\n", - 'rubyblue': ".cm-s-rubyblue.CodeMirror { background: #112435; color: white; }\n.cm-s-rubyblue div.CodeMirror-selected { background: #38566F; }\n.cm-s-rubyblue .CodeMirror-line::selection, .cm-s-rubyblue .CodeMirror-line > span::selection, .cm-s-rubyblue .CodeMirror-line > span > span::selection { background: rgba(56, 86, 111, 0.99); }\n.cm-s-rubyblue .CodeMirror-line::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 86, 111, 0.99); }\n.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }\n.cm-s-rubyblue .CodeMirror-guttermarker { color: white; }\n.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; }\n.cm-s-rubyblue .CodeMirror-linenumber { color: white; }\n.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }\n.cm-s-rubyblue span.cm-atom { color: #F4C20B; }\n.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }\n.cm-s-rubyblue span.cm-keyword { color: #F0F; }\n.cm-s-rubyblue span.cm-string { color: #F08047; }\n.cm-s-rubyblue span.cm-meta { color: #F0F; }\n.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }\n.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def, .cm-s-rubyblue span.cm-type { color: white; }\n.cm-s-rubyblue span.cm-bracket { color: #F0F; }\n.cm-s-rubyblue span.cm-link { color: #F4C20B; }\n.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }\n.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }\n.cm-s-rubyblue span.cm-error { color: #AF2018; }\n\n.cm-s-rubyblue .CodeMirror-activeline-background { background: #173047; }\n", - 'seti': "/*\n\n Name: seti\n Author: Michael Kaminsky (http://github.com/mkaminsky11)\n\n Original seti color scheme by Jesse Weed (https://github.com/jesseweed/seti-syntax)\n\n*/\n\n\n.cm-s-seti.CodeMirror {\n background-color: #151718 !important;\n color: #CFD2D1 !important;\n border: none;\n}\n.cm-s-seti .CodeMirror-gutters {\n color: #404b53;\n background-color: #0E1112;\n border: none;\n}\n.cm-s-seti .CodeMirror-cursor { border-left: solid thin #f8f8f0; }\n.cm-s-seti .CodeMirror-linenumber { color: #6D8A88; }\n.cm-s-seti.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\n.cm-s-seti .CodeMirror-line::selection, .cm-s-seti .CodeMirror-line > span::selection, .cm-s-seti .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\n.cm-s-seti .CodeMirror-line::-moz-selection, .cm-s-seti .CodeMirror-line > span::-moz-selection, .cm-s-seti .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\n.cm-s-seti span.cm-comment { color: #41535b; }\n.cm-s-seti span.cm-string, .cm-s-seti span.cm-string-2 { color: #55b5db; }\n.cm-s-seti span.cm-number { color: #cd3f45; }\n.cm-s-seti span.cm-variable { color: #55b5db; }\n.cm-s-seti span.cm-variable-2 { color: #a074c4; }\n.cm-s-seti span.cm-def { color: #55b5db; }\n.cm-s-seti span.cm-keyword { color: #ff79c6; }\n.cm-s-seti span.cm-operator { color: #9fca56; }\n.cm-s-seti span.cm-keyword { color: #e6cd69; }\n.cm-s-seti span.cm-atom { color: #cd3f45; }\n.cm-s-seti span.cm-meta { color: #55b5db; }\n.cm-s-seti span.cm-tag { color: #55b5db; }\n.cm-s-seti span.cm-attribute { color: #9fca56; }\n.cm-s-seti span.cm-qualifier { color: #9fca56; }\n.cm-s-seti span.cm-property { color: #a074c4; }\n.cm-s-seti span.cm-variable-3, .cm-s-seti span.cm-type { color: #9fca56; }\n.cm-s-seti span.cm-builtin { color: #9fca56; }\n.cm-s-seti .CodeMirror-activeline-background { background: #101213; }\n.cm-s-seti .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'shadowfox': "/*\n\n Name: shadowfox\n Author: overdodactyl (http://github.com/overdodactyl)\n\n Original shadowfox color scheme by Firefox\n\n*/\n\n.cm-s-shadowfox.CodeMirror { background: #2a2a2e; color: #b1b1b3; }\n.cm-s-shadowfox div.CodeMirror-selected { background: #353B48; }\n.cm-s-shadowfox .CodeMirror-line::selection, .cm-s-shadowfox .CodeMirror-line > span::selection, .cm-s-shadowfox .CodeMirror-line > span > span::selection { background: #353B48; }\n.cm-s-shadowfox .CodeMirror-line::-moz-selection, .cm-s-shadowfox .CodeMirror-line > span::-moz-selection, .cm-s-shadowfox .CodeMirror-line > span > span::-moz-selection { background: #353B48; }\n.cm-s-shadowfox .CodeMirror-gutters { background: #0c0c0d ; border-right: 1px solid #0c0c0d; }\n.cm-s-shadowfox .CodeMirror-guttermarker { color: #555; }\n.cm-s-shadowfox .CodeMirror-linenumber { color: #939393; }\n.cm-s-shadowfox .CodeMirror-cursor { border-left: 1px solid #fff; }\n\n.cm-s-shadowfox span.cm-comment { color: #939393; }\n.cm-s-shadowfox span.cm-atom { color: #FF7DE9; }\n.cm-s-shadowfox span.cm-quote { color: #FF7DE9; }\n.cm-s-shadowfox span.cm-builtin { color: #FF7DE9; }\n.cm-s-shadowfox span.cm-attribute { color: #FF7DE9; }\n.cm-s-shadowfox span.cm-keyword { color: #FF7DE9; }\n.cm-s-shadowfox span.cm-error { color: #FF7DE9; }\n\n.cm-s-shadowfox span.cm-number { color: #6B89FF; }\n.cm-s-shadowfox span.cm-string { color: #6B89FF; }\n.cm-s-shadowfox span.cm-string-2 { color: #6B89FF; }\n\n.cm-s-shadowfox span.cm-meta { color: #939393; }\n.cm-s-shadowfox span.cm-hr { color: #939393; }\n\n.cm-s-shadowfox span.cm-header { color: #75BFFF; }\n.cm-s-shadowfox span.cm-qualifier { color: #75BFFF; }\n.cm-s-shadowfox span.cm-variable-2 { color: #75BFFF; }\n\n.cm-s-shadowfox span.cm-property { color: #86DE74; }\n\n.cm-s-shadowfox span.cm-def { color: #75BFFF; }\n.cm-s-shadowfox span.cm-bracket { color: #75BFFF; }\n.cm-s-shadowfox span.cm-tag { color: #75BFFF; }\n.cm-s-shadowfox span.cm-link:visited { color: #75BFFF; }\n\n.cm-s-shadowfox span.cm-variable { color: #B98EFF; }\n.cm-s-shadowfox span.cm-variable-3 { color: #d7d7db; }\n.cm-s-shadowfox span.cm-link { color: #737373; }\n.cm-s-shadowfox span.cm-operator { color: #b1b1b3; }\n.cm-s-shadowfox span.cm-special { color: #d7d7db; }\n\n.cm-s-shadowfox .CodeMirror-activeline-background { background: rgba(185, 215, 253, .15) }\n.cm-s-shadowfox .CodeMirror-matchingbracket { outline: solid 1px rgba(255, 255, 255, .25); color: white !important; }\n", - 'solarized': "/*\nSolarized theme for code-mirror\nhttp://ethanschoonover.com/solarized\n*/\n\n/*\nSolarized color palette\nhttp://ethanschoonover.com/solarized/img/solarized-palette.png\n*/\n\n.solarized.base03 { color: #002b36; }\n.solarized.base02 { color: #073642; }\n.solarized.base01 { color: #586e75; }\n.solarized.base00 { color: #657b83; }\n.solarized.base0 { color: #839496; }\n.solarized.base1 { color: #93a1a1; }\n.solarized.base2 { color: #eee8d5; }\n.solarized.base3 { color: #fdf6e3; }\n.solarized.solar-yellow { color: #b58900; }\n.solarized.solar-orange { color: #cb4b16; }\n.solarized.solar-red { color: #dc322f; }\n.solarized.solar-magenta { color: #d33682; }\n.solarized.solar-violet { color: #6c71c4; }\n.solarized.solar-blue { color: #268bd2; }\n.solarized.solar-cyan { color: #2aa198; }\n.solarized.solar-green { color: #859900; }\n\n/* Color scheme for code-mirror */\n\n.cm-s-solarized {\n line-height: 1.45em;\n color-profile: sRGB;\n rendering-intent: auto;\n}\n.cm-s-solarized.cm-s-dark {\n color: #839496;\n background-color: #002b36;\n}\n.cm-s-solarized.cm-s-light {\n background-color: #fdf6e3;\n color: #657b83;\n}\n\n.cm-s-solarized .CodeMirror-widget {\n text-shadow: none;\n}\n\n.cm-s-solarized .cm-header { color: #586e75; }\n.cm-s-solarized .cm-quote { color: #93a1a1; }\n\n.cm-s-solarized .cm-keyword { color: #cb4b16; }\n.cm-s-solarized .cm-atom { color: #d33682; }\n.cm-s-solarized .cm-number { color: #d33682; }\n.cm-s-solarized .cm-def { color: #2aa198; }\n\n.cm-s-solarized .cm-variable { color: #839496; }\n.cm-s-solarized .cm-variable-2 { color: #b58900; }\n.cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; }\n\n.cm-s-solarized .cm-property { color: #2aa198; }\n.cm-s-solarized .cm-operator { color: #6c71c4; }\n\n.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }\n\n.cm-s-solarized .cm-string { color: #859900; }\n.cm-s-solarized .cm-string-2 { color: #b58900; }\n\n.cm-s-solarized .cm-meta { color: #859900; }\n.cm-s-solarized .cm-qualifier { color: #b58900; }\n.cm-s-solarized .cm-builtin { color: #d33682; }\n.cm-s-solarized .cm-bracket { color: #cb4b16; }\n.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }\n.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }\n.cm-s-solarized .cm-tag { color: #93a1a1; }\n.cm-s-solarized .cm-attribute { color: #2aa198; }\n.cm-s-solarized .cm-hr {\n color: transparent;\n border-top: 1px solid #586e75;\n display: block;\n}\n.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }\n.cm-s-solarized .cm-special { color: #6c71c4; }\n.cm-s-solarized .cm-em {\n color: #999;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.cm-s-solarized .cm-error,\n.cm-s-solarized .cm-invalidchar {\n color: #586e75;\n border-bottom: 1px dotted #dc322f;\n}\n\n.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; }\n.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); }\n.cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); }\n\n.cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; }\n.cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; }\n.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-light .CodeMirror-line > span::-moz-selection, .cm-s-light .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; }\n\n/* Editor styling */\n\n\n\n/* Little shadow on the view-port of the buffer view */\n.cm-s-solarized.CodeMirror {\n -moz-box-shadow: inset 7px 0 12px -6px #000;\n -webkit-box-shadow: inset 7px 0 12px -6px #000;\n box-shadow: inset 7px 0 12px -6px #000;\n}\n\n/* Remove gutter border */\n.cm-s-solarized .CodeMirror-gutters {\n border-right: 0;\n}\n\n/* Gutter colors and line number styling based of color scheme (dark / light) */\n\n/* Dark */\n.cm-s-solarized.cm-s-dark .CodeMirror-gutters {\n background-color: #073642;\n}\n\n.cm-s-solarized.cm-s-dark .CodeMirror-linenumber {\n color: #586e75;\n}\n\n/* Light */\n.cm-s-solarized.cm-s-light .CodeMirror-gutters {\n background-color: #eee8d5;\n}\n\n.cm-s-solarized.cm-s-light .CodeMirror-linenumber {\n color: #839496;\n}\n\n/* Common */\n.cm-s-solarized .CodeMirror-linenumber {\n padding: 0 5px;\n}\n.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }\n.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }\n.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }\n\n.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {\n color: #586e75;\n}\n\n/* Cursor */\n.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; }\n\n/* Fat cursor */\n.cm-s-solarized.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; }\n.cm-s-solarized.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; }\n.cm-s-solarized.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: #586e75; }\n.cm-s-solarized.cm-s-dark .cm-animate-fat-cursor { background-color: #586e75; }\n\n/* Active line */\n.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {\n background: rgba(255, 255, 255, 0.06);\n}\n.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {\n background: rgba(0, 0, 0, 0.06);\n}\n", - 'ssms': ".cm-s-ssms span.cm-keyword { color: blue; }\n.cm-s-ssms span.cm-comment { color: darkgreen; }\n.cm-s-ssms span.cm-string { color: red; }\n.cm-s-ssms span.cm-def { color: black; }\n.cm-s-ssms span.cm-variable { color: black; }\n.cm-s-ssms span.cm-variable-2 { color: black; }\n.cm-s-ssms span.cm-atom { color: darkgray; }\n.cm-s-ssms .CodeMirror-linenumber { color: teal; }\n.cm-s-ssms .CodeMirror-activeline-background { background: #ffffff; }\n.cm-s-ssms span.cm-string-2 { color: #FF00FF; }\n.cm-s-ssms span.cm-operator, \n.cm-s-ssms span.cm-bracket, \n.cm-s-ssms span.cm-punctuation { color: darkgray; }\n.cm-s-ssms .CodeMirror-gutters { border-right: 3px solid #ffee62; background-color: #ffffff; }\n.cm-s-ssms div.CodeMirror-selected { background: #ADD6FF; }\n\n", - 'the-matrix': ".cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }\n.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D; }\n.cm-s-the-matrix .CodeMirror-line::selection, .cm-s-the-matrix .CodeMirror-line > span::selection, .cm-s-the-matrix .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-the-matrix .CodeMirror-line::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }\n.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; }\n.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; }\n.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }\n.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00; }\n\n.cm-s-the-matrix span.cm-keyword { color: #008803; font-weight: bold; }\n.cm-s-the-matrix span.cm-atom { color: #3FF; }\n.cm-s-the-matrix span.cm-number { color: #FFB94F; }\n.cm-s-the-matrix span.cm-def { color: #99C; }\n.cm-s-the-matrix span.cm-variable { color: #F6C; }\n.cm-s-the-matrix span.cm-variable-2 { color: #C6F; }\n.cm-s-the-matrix span.cm-variable-3, .cm-s-the-matrix span.cm-type { color: #96F; }\n.cm-s-the-matrix span.cm-property { color: #62FFA0; }\n.cm-s-the-matrix span.cm-operator { color: #999; }\n.cm-s-the-matrix span.cm-comment { color: #CCCCCC; }\n.cm-s-the-matrix span.cm-string { color: #39C; }\n.cm-s-the-matrix span.cm-meta { color: #C9F; }\n.cm-s-the-matrix span.cm-qualifier { color: #FFF700; }\n.cm-s-the-matrix span.cm-builtin { color: #30a; }\n.cm-s-the-matrix span.cm-bracket { color: #cc7; }\n.cm-s-the-matrix span.cm-tag { color: #FFBD40; }\n.cm-s-the-matrix span.cm-attribute { color: #FFF700; }\n.cm-s-the-matrix span.cm-error { color: #FF0000; }\n\n.cm-s-the-matrix .CodeMirror-activeline-background { background: #040; }\n", - 'tomorrow-night-bright': "/*\n\n Name: Tomorrow Night - Bright\n Author: Chris Kempson\n\n Port done by Gerard Braad \n\n*/\n\n.cm-s-tomorrow-night-bright.CodeMirror { background: #000000; color: #eaeaea; }\n.cm-s-tomorrow-night-bright div.CodeMirror-selected { background: #424242; }\n.cm-s-tomorrow-night-bright .CodeMirror-gutters { background: #000000; border-right: 0px; }\n.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; }\n.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; }\n.cm-s-tomorrow-night-bright .CodeMirror-linenumber { color: #424242; }\n.cm-s-tomorrow-night-bright .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }\n\n.cm-s-tomorrow-night-bright span.cm-comment { color: #d27b53; }\n.cm-s-tomorrow-night-bright span.cm-atom { color: #a16a94; }\n.cm-s-tomorrow-night-bright span.cm-number { color: #a16a94; }\n\n.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute { color: #99cc99; }\n.cm-s-tomorrow-night-bright span.cm-keyword { color: #d54e53; }\n.cm-s-tomorrow-night-bright span.cm-string { color: #e7c547; }\n\n.cm-s-tomorrow-night-bright span.cm-variable { color: #b9ca4a; }\n.cm-s-tomorrow-night-bright span.cm-variable-2 { color: #7aa6da; }\n.cm-s-tomorrow-night-bright span.cm-def { color: #e78c45; }\n.cm-s-tomorrow-night-bright span.cm-bracket { color: #eaeaea; }\n.cm-s-tomorrow-night-bright span.cm-tag { color: #d54e53; }\n.cm-s-tomorrow-night-bright span.cm-link { color: #a16a94; }\n.cm-s-tomorrow-night-bright span.cm-error { background: #d54e53; color: #6A6A6A; }\n\n.cm-s-tomorrow-night-bright .CodeMirror-activeline-background { background: #2a2a2a; }\n.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'tomorrow-night-eighties': "/*\n\n Name: Tomorrow Night - Eighties\n Author: Chris Kempson\n\n CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-tomorrow-night-eighties.CodeMirror { background: #000000; color: #CCCCCC; }\n.cm-s-tomorrow-night-eighties div.CodeMirror-selected { background: #2D2D2D; }\n.cm-s-tomorrow-night-eighties .CodeMirror-line::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-tomorrow-night-eighties .CodeMirror-line::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-tomorrow-night-eighties .CodeMirror-gutters { background: #000000; border-right: 0px; }\n.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; }\n.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; }\n.cm-s-tomorrow-night-eighties .CodeMirror-linenumber { color: #515151; }\n.cm-s-tomorrow-night-eighties .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }\n\n.cm-s-tomorrow-night-eighties span.cm-comment { color: #d27b53; }\n.cm-s-tomorrow-night-eighties span.cm-atom { color: #a16a94; }\n.cm-s-tomorrow-night-eighties span.cm-number { color: #a16a94; }\n\n.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute { color: #99cc99; }\n.cm-s-tomorrow-night-eighties span.cm-keyword { color: #f2777a; }\n.cm-s-tomorrow-night-eighties span.cm-string { color: #ffcc66; }\n\n.cm-s-tomorrow-night-eighties span.cm-variable { color: #99cc99; }\n.cm-s-tomorrow-night-eighties span.cm-variable-2 { color: #6699cc; }\n.cm-s-tomorrow-night-eighties span.cm-def { color: #f99157; }\n.cm-s-tomorrow-night-eighties span.cm-bracket { color: #CCCCCC; }\n.cm-s-tomorrow-night-eighties span.cm-tag { color: #f2777a; }\n.cm-s-tomorrow-night-eighties span.cm-link { color: #a16a94; }\n.cm-s-tomorrow-night-eighties span.cm-error { background: #f2777a; color: #6A6A6A; }\n\n.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background { background: #343600; }\n.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\n", - 'ttcn': ".cm-s-ttcn .cm-quote { color: #090; }\n.cm-s-ttcn .cm-negative { color: #d44; }\n.cm-s-ttcn .cm-positive { color: #292; }\n.cm-s-ttcn .cm-header, .cm-strong { font-weight: bold; }\n.cm-s-ttcn .cm-em { font-style: italic; }\n.cm-s-ttcn .cm-link { text-decoration: underline; }\n.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; }\n.cm-s-ttcn .cm-header { color: #00f; font-weight: bold; }\n\n.cm-s-ttcn .cm-atom { color: #219; }\n.cm-s-ttcn .cm-attribute { color: #00c; }\n.cm-s-ttcn .cm-bracket { color: #997; }\n.cm-s-ttcn .cm-comment { color: #333333; }\n.cm-s-ttcn .cm-def { color: #00f; }\n.cm-s-ttcn .cm-em { font-style: italic; }\n.cm-s-ttcn .cm-error { color: #f00; }\n.cm-s-ttcn .cm-hr { color: #999; }\n.cm-s-ttcn .cm-invalidchar { color: #f00; }\n.cm-s-ttcn .cm-keyword { font-weight:bold; }\n.cm-s-ttcn .cm-link { color: #00c; text-decoration: underline; }\n.cm-s-ttcn .cm-meta { color: #555; }\n.cm-s-ttcn .cm-negative { color: #d44; }\n.cm-s-ttcn .cm-positive { color: #292; }\n.cm-s-ttcn .cm-qualifier { color: #555; }\n.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; }\n.cm-s-ttcn .cm-string { color: #006400; }\n.cm-s-ttcn .cm-string-2 { color: #f50; }\n.cm-s-ttcn .cm-strong { font-weight: bold; }\n.cm-s-ttcn .cm-tag { color: #170; }\n.cm-s-ttcn .cm-variable { color: #8B2252; }\n.cm-s-ttcn .cm-variable-2 { color: #05a; }\n.cm-s-ttcn .cm-variable-3, .cm-s-ttcn .cm-type { color: #085; }\n\n.cm-s-ttcn .cm-invalidchar { color: #f00; }\n\n/* ASN */\n.cm-s-ttcn .cm-accessTypes,\n.cm-s-ttcn .cm-compareTypes { color: #27408B; }\n.cm-s-ttcn .cm-cmipVerbs { color: #8B2252; }\n.cm-s-ttcn .cm-modifier { color:#D2691E; }\n.cm-s-ttcn .cm-status { color:#8B4545; }\n.cm-s-ttcn .cm-storage { color:#A020F0; }\n.cm-s-ttcn .cm-tags { color:#006400; }\n\n/* CFG */\n.cm-s-ttcn .cm-externalCommands { color: #8B4545; font-weight:bold; }\n.cm-s-ttcn .cm-fileNCtrlMaskOptions,\n.cm-s-ttcn .cm-sectionTitle { color: #2E8B57; font-weight:bold; }\n\n/* TTCN */\n.cm-s-ttcn .cm-booleanConsts,\n.cm-s-ttcn .cm-otherConsts,\n.cm-s-ttcn .cm-verdictConsts { color: #006400; }\n.cm-s-ttcn .cm-configOps,\n.cm-s-ttcn .cm-functionOps,\n.cm-s-ttcn .cm-portOps,\n.cm-s-ttcn .cm-sutOps,\n.cm-s-ttcn .cm-timerOps,\n.cm-s-ttcn .cm-verdictOps { color: #0000FF; }\n.cm-s-ttcn .cm-preprocessor,\n.cm-s-ttcn .cm-templateMatch,\n.cm-s-ttcn .cm-ttcn3Macros { color: #27408B; }\n.cm-s-ttcn .cm-types { color: #A52A2A; font-weight:bold; }\n.cm-s-ttcn .cm-visibilityModifiers { font-weight:bold; }\n", - 'twilight': ".cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/\n.cm-s-twilight div.CodeMirror-selected { background: #323232; } /**/\n.cm-s-twilight .CodeMirror-line::selection, .cm-s-twilight .CodeMirror-line > span::selection, .cm-s-twilight .CodeMirror-line > span > span::selection { background: rgba(50, 50, 50, 0.99); }\n.cm-s-twilight .CodeMirror-line::-moz-selection, .cm-s-twilight .CodeMirror-line > span::-moz-selection, .cm-s-twilight .CodeMirror-line > span > span::-moz-selection { background: rgba(50, 50, 50, 0.99); }\n\n.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; }\n.cm-s-twilight .CodeMirror-guttermarker { color: white; }\n.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; }\n.cm-s-twilight .CodeMirror-linenumber { color: #aaa; }\n.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/\n.cm-s-twilight .cm-atom { color: #FC0; }\n.cm-s-twilight .cm-number { color: #ca7841; } /**/\n.cm-s-twilight .cm-def { color: #8DA6CE; }\n.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/\n.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def, .cm-s-twilight span.cm-type { color: #607392; } /**/\n.cm-s-twilight .cm-operator { color: #cda869; } /**/\n.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/\n.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/\n.cm-s-twilight .cm-string-2 { color:#bd6b18; } /*?*/\n.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/\n.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/\n.cm-s-twilight .cm-tag { color: #997643; } /**/\n.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/\n.cm-s-twilight .cm-header { color: #FF6400; }\n.cm-s-twilight .cm-hr { color: #AEAEAE; }\n.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/\n.cm-s-twilight .cm-error { border-bottom: 1px solid red; }\n\n.cm-s-twilight .CodeMirror-activeline-background { background: #27282E; }\n.cm-s-twilight .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\n", - 'vibrant-ink': "/* Taken from the popular Visual Studio Vibrant Ink Schema */\n\n.cm-s-vibrant-ink.CodeMirror { background: black; color: white; }\n.cm-s-vibrant-ink div.CodeMirror-selected { background: #35493c; }\n.cm-s-vibrant-ink .CodeMirror-line::selection, .cm-s-vibrant-ink .CodeMirror-line > span::selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::selection { background: rgba(53, 73, 60, 0.99); }\n.cm-s-vibrant-ink .CodeMirror-line::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::-moz-selection { background: rgba(53, 73, 60, 0.99); }\n\n.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\n.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; }\n.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-vibrant-ink .cm-keyword { color: #CC7832; }\n.cm-s-vibrant-ink .cm-atom { color: #FC0; }\n.cm-s-vibrant-ink .cm-number { color: #FFEE98; }\n.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }\n.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D; }\n.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def, .cm-s-vibrant span.cm-type { color: #FFC66D; }\n.cm-s-vibrant-ink .cm-operator { color: #888; }\n.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }\n.cm-s-vibrant-ink .cm-string { color: #A5C25C; }\n.cm-s-vibrant-ink .cm-string-2 { color: red; }\n.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }\n.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }\n.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }\n.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }\n.cm-s-vibrant-ink .cm-header { color: #FF6400; }\n.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }\n.cm-s-vibrant-ink .cm-link { color: #5656F3; }\n.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }\n\n.cm-s-vibrant-ink .CodeMirror-activeline-background { background: #27282E; }\n.cm-s-vibrant-ink .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\n", - 'xq-dark': "/*\nCopyright (C) 2011 by MarkLogic Corporation\nAuthor: Mike Brevoort \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; }\n.cm-s-xq-dark div.CodeMirror-selected { background: #27007A; }\n.cm-s-xq-dark .CodeMirror-line::selection, .cm-s-xq-dark .CodeMirror-line > span::selection, .cm-s-xq-dark .CodeMirror-line > span > span::selection { background: rgba(39, 0, 122, 0.99); }\n.cm-s-xq-dark .CodeMirror-line::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 0, 122, 0.99); }\n.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\n.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; }\n.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; }\n.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; }\n.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white; }\n\n.cm-s-xq-dark span.cm-keyword { color: #FFBD40; }\n.cm-s-xq-dark span.cm-atom { color: #6C8CD5; }\n.cm-s-xq-dark span.cm-number { color: #164; }\n.cm-s-xq-dark span.cm-def { color: #FFF; text-decoration:underline; }\n.cm-s-xq-dark span.cm-variable { color: #FFF; }\n.cm-s-xq-dark span.cm-variable-2 { color: #EEE; }\n.cm-s-xq-dark span.cm-variable-3, .cm-s-xq-dark span.cm-type { color: #DDD; }\n.cm-s-xq-dark span.cm-property {}\n.cm-s-xq-dark span.cm-operator {}\n.cm-s-xq-dark span.cm-comment { color: gray; }\n.cm-s-xq-dark span.cm-string { color: #9FEE00; }\n.cm-s-xq-dark span.cm-meta { color: yellow; }\n.cm-s-xq-dark span.cm-qualifier { color: #FFF700; }\n.cm-s-xq-dark span.cm-builtin { color: #30a; }\n.cm-s-xq-dark span.cm-bracket { color: #cc7; }\n.cm-s-xq-dark span.cm-tag { color: #FFBD40; }\n.cm-s-xq-dark span.cm-attribute { color: #FFF700; }\n.cm-s-xq-dark span.cm-error { color: #f00; }\n\n.cm-s-xq-dark .CodeMirror-activeline-background { background: #27282E; }\n.cm-s-xq-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\n", - 'xq-light': "/*\nCopyright (C) 2011 by MarkLogic Corporation\nAuthor: Mike Brevoort \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n.cm-s-xq-light span.cm-keyword { line-height: 1em; font-weight: bold; color: #5A5CAD; }\n.cm-s-xq-light span.cm-atom { color: #6C8CD5; }\n.cm-s-xq-light span.cm-number { color: #164; }\n.cm-s-xq-light span.cm-def { text-decoration:underline; }\n.cm-s-xq-light span.cm-variable { color: black; }\n.cm-s-xq-light span.cm-variable-2 { color:black; }\n.cm-s-xq-light span.cm-variable-3, .cm-s-xq-light span.cm-type { color: black; }\n.cm-s-xq-light span.cm-property {}\n.cm-s-xq-light span.cm-operator {}\n.cm-s-xq-light span.cm-comment { color: #0080FF; font-style: italic; }\n.cm-s-xq-light span.cm-string { color: red; }\n.cm-s-xq-light span.cm-meta { color: yellow; }\n.cm-s-xq-light span.cm-qualifier { color: grey; }\n.cm-s-xq-light span.cm-builtin { color: #7EA656; }\n.cm-s-xq-light span.cm-bracket { color: #cc7; }\n.cm-s-xq-light span.cm-tag { color: #3F7F7F; }\n.cm-s-xq-light span.cm-attribute { color: #7F007F; }\n.cm-s-xq-light span.cm-error { color: #f00; }\n\n.cm-s-xq-light .CodeMirror-activeline-background { background: #e8f2ff; }\n.cm-s-xq-light .CodeMirror-matchingbracket { outline:1px solid grey;color:black !important;background:yellow; }\n", - 'yeti': "/*\n\n Name: yeti\n Author: Michael Kaminsky (http://github.com/mkaminsky11)\n\n Original yeti color scheme by Jesse Weed (https://github.com/jesseweed/yeti-syntax)\n\n*/\n\n\n.cm-s-yeti.CodeMirror {\n background-color: #ECEAE8 !important;\n color: #d1c9c0 !important;\n border: none;\n}\n\n.cm-s-yeti .CodeMirror-gutters {\n color: #adaba6;\n background-color: #E5E1DB;\n border: none;\n}\n.cm-s-yeti .CodeMirror-cursor { border-left: solid thin #d1c9c0; }\n.cm-s-yeti .CodeMirror-linenumber { color: #adaba6; }\n.cm-s-yeti.CodeMirror-focused div.CodeMirror-selected { background: #DCD8D2; }\n.cm-s-yeti .CodeMirror-line::selection, .cm-s-yeti .CodeMirror-line > span::selection, .cm-s-yeti .CodeMirror-line > span > span::selection { background: #DCD8D2; }\n.cm-s-yeti .CodeMirror-line::-moz-selection, .cm-s-yeti .CodeMirror-line > span::-moz-selection, .cm-s-yeti .CodeMirror-line > span > span::-moz-selection { background: #DCD8D2; }\n.cm-s-yeti span.cm-comment { color: #d4c8be; }\n.cm-s-yeti span.cm-string, .cm-s-yeti span.cm-string-2 { color: #96c0d8; }\n.cm-s-yeti span.cm-number { color: #a074c4; }\n.cm-s-yeti span.cm-variable { color: #55b5db; }\n.cm-s-yeti span.cm-variable-2 { color: #a074c4; }\n.cm-s-yeti span.cm-def { color: #55b5db; }\n.cm-s-yeti span.cm-operator { color: #9fb96e; }\n.cm-s-yeti span.cm-keyword { color: #9fb96e; }\n.cm-s-yeti span.cm-atom { color: #a074c4; }\n.cm-s-yeti span.cm-meta { color: #96c0d8; }\n.cm-s-yeti span.cm-tag { color: #96c0d8; }\n.cm-s-yeti span.cm-attribute { color: #9fb96e; }\n.cm-s-yeti span.cm-qualifier { color: #96c0d8; }\n.cm-s-yeti span.cm-property { color: #a074c4; }\n.cm-s-yeti span.cm-builtin { color: #a074c4; }\n.cm-s-yeti span.cm-variable-3, .cm-s-yeti span.cm-type { color: #96c0d8; }\n.cm-s-yeti .CodeMirror-activeline-background { background: #E7E4E0; }\n.cm-s-yeti .CodeMirror-matchingbracket { text-decoration: underline; }\n", - 'yonce': "/*\n\n Name: yoncé\n Author: Thomas MacLean (http://github.com/thomasmaclean)\n\n Original yoncé color scheme by Mina Markham (https://github.com/minamarkham)\n\n*/\n\n.cm-s-yonce.CodeMirror { background: #1C1C1C; color: #d4d4d4; } /**/\n.cm-s-yonce div.CodeMirror-selected { background: rgba(252, 69, 133, 0.478); } /**/\n.cm-s-yonce .CodeMirror-selectedtext,\n.cm-s-yonce .CodeMirror-selected,\n.cm-s-yonce .CodeMirror-line::selection,\n.cm-s-yonce .CodeMirror-line > span::selection,\n.cm-s-yonce .CodeMirror-line > span > span::selection,\n.cm-s-yonce .CodeMirror-line::-moz-selection,\n.cm-s-yonce .CodeMirror-line > span::-moz-selection,\n.cm-s-yonce .CodeMirror-line > span > span::-moz-selection { background: rgba(252, 67, 132, 0.47); }\n\n.cm-s-yonce.CodeMirror pre { padding-left: 0px; }\n.cm-s-yonce .CodeMirror-gutters {background: #1C1C1C; border-right: 0px;}\n.cm-s-yonce .CodeMirror-linenumber {color: #777777; padding-right: 10px; }\n.cm-s-yonce .CodeMirror-activeline .CodeMirror-linenumber.CodeMirror-gutter-elt { background: #1C1C1C; color: #fc4384; }\n.cm-s-yonce .CodeMirror-linenumber { color: #777; }\n.cm-s-yonce .CodeMirror-cursor { border-left: 2px solid #FC4384; }\n.cm-s-yonce .cm-searching { background: rgba(243, 155, 53, .3) !important; outline: 1px solid #F39B35; }\n.cm-s-yonce .cm-searching.CodeMirror-selectedtext { background: rgba(243, 155, 53, .7) !important; color: white; }\n\n.cm-s-yonce .cm-keyword { color: #00A7AA; } /**/\n.cm-s-yonce .cm-atom { color: #F39B35; }\n.cm-s-yonce .cm-number, .cm-s-yonce span.cm-type { color: #A06FCA; } /**/\n.cm-s-yonce .cm-def { color: #98E342; }\n.cm-s-yonce .cm-property,\n.cm-s-yonce span.cm-variable { color: #D4D4D4; font-style: italic; }\n.cm-s-yonce span.cm-variable-2 { color: #da7dae; font-style: italic; }\n.cm-s-yonce span.cm-variable-3 { color: #A06FCA; }\n.cm-s-yonce .cm-type.cm-def { color: #FC4384; font-style: normal; text-decoration: underline; }\n.cm-s-yonce .cm-property.cm-def { color: #FC4384; font-style: normal; }\n.cm-s-yonce .cm-callee { color: #FC4384; font-style: normal; }\n.cm-s-yonce .cm-operator { color: #FC4384; } /**/\n.cm-s-yonce .cm-qualifier,\n.cm-s-yonce .cm-tag { color: #FC4384; }\n.cm-s-yonce .cm-tag.cm-bracket { color: #D4D4D4; }\n.cm-s-yonce .cm-attribute { color: #A06FCA; }\n.cm-s-yonce .cm-comment { color:#696d70; font-style:italic; font-weight:normal; } /**/\n.cm-s-yonce .cm-comment.cm-tag { color: #FC4384 }\n.cm-s-yonce .cm-comment.cm-attribute { color: #D4D4D4; }\n.cm-s-yonce .cm-string { color:#E6DB74; } /**/\n.cm-s-yonce .cm-string-2 { color:#F39B35; } /*?*/\n.cm-s-yonce .cm-meta { color: #D4D4D4; background: inherit; }\n.cm-s-yonce .cm-builtin { color: #FC4384; } /*?*/\n.cm-s-yonce .cm-header { color: #da7dae; }\n.cm-s-yonce .cm-hr { color: #98E342; }\n.cm-s-yonce .cm-link { color:#696d70; font-style:italic; text-decoration:none; } /**/\n.cm-s-yonce .cm-error { border-bottom: 1px solid #C42412; }\n\n.cm-s-yonce .CodeMirror-activeline-background { background: #272727; }\n.cm-s-yonce .CodeMirror-matchingbracket { outline:1px solid grey; color:#D4D4D4 !important; }\n", - 'zenburn': "/**\n * \"\n * Using Zenburn color palette from the Emacs Zenburn Theme\n * https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el\n *\n * Also using parts of https://github.com/xavi/coderay-lighttable-theme\n * \"\n * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css\n */\n\n.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; }\n.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; }\n.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white; }\n.cm-s-zenburn.CodeMirror { background-color: #3f3f3f; color: #dcdccc; }\n.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; }\n.cm-s-zenburn span.cm-comment { color: #7f9f7f; }\n.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; }\n.cm-s-zenburn span.cm-atom { color: #bfebbf; }\n.cm-s-zenburn span.cm-def { color: #dcdccc; }\n.cm-s-zenburn span.cm-variable { color: #dfaf8f; }\n.cm-s-zenburn span.cm-variable-2 { color: #dcdccc; }\n.cm-s-zenburn span.cm-string { color: #cc9393; }\n.cm-s-zenburn span.cm-string-2 { color: #cc9393; }\n.cm-s-zenburn span.cm-number { color: #dcdccc; }\n.cm-s-zenburn span.cm-tag { color: #93e0e3; }\n.cm-s-zenburn span.cm-property { color: #dfaf8f; }\n.cm-s-zenburn span.cm-attribute { color: #dfaf8f; }\n.cm-s-zenburn span.cm-qualifier { color: #7cb8bb; }\n.cm-s-zenburn span.cm-meta { color: #f0dfaf; }\n.cm-s-zenburn span.cm-header { color: #f0efd0; }\n.cm-s-zenburn span.cm-operator { color: #f0efd0; }\n.cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; }\n.cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; }\n.cm-s-zenburn .CodeMirror-activeline { background: #000000; }\n.cm-s-zenburn .CodeMirror-activeline-background { background: #000000; }\n.cm-s-zenburn div.CodeMirror-selected { background: #545454; }\n.cm-s-zenburn .CodeMirror-focused div.CodeMirror-selected { background: #4f4f4f; }\n", -}; +const CODEMIRROR_THEMES = [ + '3024-day', + '3024-night', + 'abbott', + 'abcdef', + 'ambiance-mobile', + 'ambiance', + 'ayu-dark', + 'ayu-mirage', + 'base16-dark', + 'base16-light', + 'bespin', + 'blackboard', + 'cobalt', + 'colorforth', + 'darcula', + 'dracula', + 'duotone-dark', + 'duotone-light', + 'eclipse', + 'elegant', + 'erlang-dark', + 'gruvbox-dark', + 'hopscotch', + 'icecoder', + 'idea', + 'isotope', + 'juejin', + 'lesser-dark', + 'liquibyte', + 'lucario', + 'material-darker', + 'material-ocean', + 'material-palenight', + 'material', + 'mbo', + 'mdn-like', + 'midnight', + 'monokai', + 'moxer', + 'neat', + 'neo', + 'night', + 'nord', + 'oceanic-next', + 'panda-syntax', + 'paraiso-dark', + 'paraiso-light', + 'pastel-on-dark', + 'railscasts', + 'rubyblue', + 'seti', + 'shadowfox', + 'solarized', + 'ssms', + 'the-matrix', + 'tomorrow-night-bright', + 'tomorrow-night-eighties', + 'ttcn', + 'twilight', + 'vibrant-ink', + 'xq-dark', + 'xq-light', + 'yeti', + 'yonce', + 'zenburn', +]; +export default CODEMIRROR_THEMES; diff --git a/src/edit/compact-header.js b/src/edit/compact-header.js new file mode 100644 index 00000000000..f632d497a44 --- /dev/null +++ b/src/edit/compact-header.js @@ -0,0 +1,47 @@ +import {$, $$, $create, important} from '/js/dom'; +import * as prefs from '/js/prefs'; +import editor from './editor'; + +export default function CompactHeader() { + // Set up mini-header on scroll + const {isUsercss} = editor; + const el = $create({ + style: important(` + top: 0; + height: 1px; + position: absolute; + visibility: hidden; + `), + }); + const scroller = isUsercss ? $('.CodeMirror-scroll') : document.body; + const xoRoot = isUsercss ? scroller : undefined; + const xo = new IntersectionObserver(onScrolled, {root: xoRoot}); + const elInfo = $('h1 a'); + scroller.appendChild(el); + onCompactToggled(editor.mqCompact); + editor.mqCompact.on('change', onCompactToggled); + + /** @param {MediaQueryList} mq */ + function onCompactToggled(mq) { + for (const el of $$('details[data-pref]')) { + el.open = mq.matches ? false : + el.classList.contains('ignore-pref') ? el.open : + prefs.get(el.dataset.pref); + } + if (mq.matches) { + xo.observe(el); + $('#basic-info-name').after(elInfo); + } else { + xo.disconnect(); + $('h1').append(elInfo); + } + } + + /** @param {IntersectionObserverEntry[]} entries */ + function onScrolled(entries) { + const h = $('#header'); + const sticky = !entries.pop().intersectionRatio; + if (!isUsercss) scroller.style.paddingTop = sticky ? h.offsetHeight + 'px' : ''; + h.classList.toggle('sticky', sticky); + } +} diff --git a/src/edit/drafts.js b/src/edit/drafts.js index 5035d8fa248..4bb0fc42b3d 100644 --- a/src/edit/drafts.js +++ b/src/edit/drafts.js @@ -1,33 +1,30 @@ -/* global $create */// dom.js -/* global API */// msg.js -/* global clamp debounce */// toolbox.js -/* global editor */ -/* global MozDocMapper */// sections-util.js -/* global helpPopup showCodeMirrorPopup */// util.js -/* global prefs */ -/* global t */// localization.js -'use strict'; +import {$create} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {MozDocMapper} from '/js/sections-util'; +import {clamp, debounce} from '/js/toolbox'; +import editor from './editor'; +import {helpPopup, showCodeMirrorPopup} from './util'; -(async function AutosaveDrafts() { +export default async function Drafts() { const makeId = () => editor.style.id || 'new'; let delay; let port; - connectPort(); - await maybeRestore(); - editor.dirty.onChange(isDirty => isDirty ? connectPort() : port.disconnect()); - editor.dirty.onDataChange(isDirty => debounce(updateDraft, isDirty ? delay : 0)); - prefs.subscribe('editor.autosaveDraft', (key, val) => { - delay = clamp(val * 1000 | 0, 1000, 2 ** 32 - 1); - const t = debounce.timers.get(updateDraft); - if (t) debounce(updateDraft, t.delay ? delay : 0); - }, true); + connectPort(); + maybeRestore().then(() => { + editor.dirty.onChange(isDirty => isDirty ? connectPort() : port.disconnect()); + editor.dirty.onDataChange(isDirty => debounce(updateDraft, isDirty ? delay : 0)); + prefs.subscribe('editor.autosaveDraft', (key, val) => { + delay = clamp(val * 1000 | 0, 1000, 2 ** 32 - 1); + const t = debounce.timers.get(updateDraft); + if (t) debounce(updateDraft, t.delay ? delay : 0); + }, true); + }); async function maybeRestore() { - const [draft] = await Promise.all([ - API.drafts.get(makeId()), - require(['/js/dlg/message-box.css']), - ]); + const draft = await API.drafts.get(makeId()); if (!draft || draft.isUsercss !== editor.isUsercss || editor.isSame(draft.style)) { return; } @@ -67,4 +64,4 @@ si: editor.makeScrollInfo(), }, makeId()); } -})(); +} diff --git a/src/edit/edit.js b/src/edit/edit.js deleted file mode 100644 index b40ea9dd505..00000000000 --- a/src/edit/edit.js +++ /dev/null @@ -1,412 +0,0 @@ -/* global $$ $ $create important */// dom.js -/* global API msg */// msg.js -/* global CodeMirror */ -/* global SectionsEditor */ -/* global SourceEditor */ -/* global validateRegexp */// util.js -/* global clipString closeCurrentTab deepEqual mapObj sessionStore */// toolbox.js -/* global cmFactory */ -/* global editor EditorHeader */// base.js -/* global linterMan */ -/* global prefs */ -/* global t */// localization.js -'use strict'; - -//#region init - -t.body(); - -editor.styleReady.then(async () => { - EditorHeader(); - EditorMethods(); - await (editor.isUsercss ? SourceEditor : SectionsEditor)(); - - editor.dirty.onChange(editor.updateDirty); - prefs.subscribe('editor.linter', () => linterMan.run()); - - // enabling after init to prevent flash of validation failure on an empty name - $('#name').required = !editor.isUsercss; - $('#save-button').onclick = editor.save; - $('#cancel-button').onclick = editor.cancel; - - const elSec = $('#sections-list'); - const elToc = $('#toc'); - const moDetails = new MutationObserver(([{target: sec}]) => { - if (!sec.open) return; - if (sec === elSec) editor.updateToc(); - const el = sec.lastElementChild; - const s = el.style; - const x2 = sec.getBoundingClientRect().left + el.getBoundingClientRect().width; - if (x2 > innerWidth - 30) s.right = '0'; - else if (s.right) s.removeProperty('right'); - }); - // editor.toc.expanded pref isn't saved in compact-layout so prefs.subscribe won't work - if (elSec.open) editor.updateToc(); - // and we also toggle `open` directly in other places e.g. in detectLayout() - for (const el of $$('#details-wrapper > details')) { - moDetails.observe(el, {attributes: true, attributeFilter: ['open']}); - } - elToc.onclick = e => - editor.jumpToEditor([].indexOf.call(elToc.children, e.target)); - $('#lint-help').onclick = () => - require(['/edit/linter-dialogs'], () => linterMan.showLintHelp()); - - require([ - '/edit/autocomplete', - '/edit/drafts', - '/edit/global-search', - ]); -}); - -editor.styleReady.then(async () => { - // Set up mini-header on scroll - const {isUsercss} = editor; - const el = $create({ - style: important(` - top: 0; - height: 1px; - position: absolute; - visibility: hidden; - `), - }); - const scroller = isUsercss ? $('.CodeMirror-scroll') : document.body; - const xoRoot = isUsercss ? scroller : undefined; - const xo = new IntersectionObserver(onScrolled, {root: xoRoot}); - const elInfo = $('h1 a'); - scroller.appendChild(el); - onCompactToggled(editor.mqCompact); - editor.mqCompact.on('change', onCompactToggled); - - /** @param {MediaQueryList} mq */ - function onCompactToggled(mq) { - for (const el of $$('details[data-pref]')) { - el.open = mq.matches ? false : - el.classList.contains('ignore-pref') ? el.open : - prefs.get(el.dataset.pref); - } - if (mq.matches) { - xo.observe(el); - $('#basic-info-name').after(elInfo); - } else { - xo.disconnect(); - $('h1').append(elInfo); - } - } - /** @param {IntersectionObserverEntry[]} entries */ - function onScrolled(entries) { - const h = $('#header'); - const sticky = !entries.pop().intersectionRatio; - if (!isUsercss) scroller.style.paddingTop = sticky ? h.offsetHeight + 'px' : ''; - h.classList.toggle('sticky', sticky); - } -}); - -//#endregion -//#region events - -msg.onExtension(request => { - const {style} = request; - switch (request.method) { - case 'styleUpdated': - if (editor.style.id === style.id) { - handleExternalUpdate(request); - } - break; - case 'styleDeleted': - if (editor.style.id === style.id) { - closeCurrentTab(); - } - break; - } -}); - -async function handleExternalUpdate({style, reason}) { - if (reason === 'editPreview' || - reason === 'editPreviewEnd') { - return; - } - if (reason === 'editSave' && editor.saving) { - editor.saving = false; - return; - } - if (reason === 'toggle') { - if (editor.dirty.isDirty()) { - editor.toggleStyle(style.enabled); - // updateLivePreview is called by toggleStyle - } else { - Object.assign(editor.style, style); - editor.updateLivePreview(); - } - editor.updateMeta(); - return; - } - style = await API.styles.get(style.id); - if (reason === 'config') { - for (const key in editor.style) if (!(key in style)) delete editor.style[key]; - delete style.sourceCode; - delete style.sections; - delete style.name; - delete style.enabled; - Object.assign(editor.style, style); - editor.updateLivePreview(); - } else { - await editor.replaceStyle(style); - } - window.dispatchEvent(new Event('styleSettings')); -} - -window.on('beforeunload', e => { - let pos; - if (editor.isWindowed && - document.visibilityState === 'visible' && - prefs.get('openEditInWindow') && - screenX !== -32000 && // Chrome uses this value for minimized windows - ( // only if not maximized - screenX > 0 || outerWidth < screen.availWidth || - screenY > 0 || outerHeight < screen.availHeight || - screenX <= -10 || outerWidth >= screen.availWidth + 10 || - screenY <= -10 || outerHeight >= screen.availHeight + 10 - ) - ) { - pos = { - left: screenX, - top: screenY, - width: outerWidth, - height: outerHeight, - }; - prefs.set('windowPosition', pos); - } - sessionStore.windowPos = JSON.stringify(pos || {}); - API.data.set('editorScrollInfo' + editor.style.id, editor.makeScrollInfo()); - const activeElement = document.activeElement; - if (activeElement) { - // blurring triggers 'change' or 'input' event if needed - activeElement.blur(); - // refocus if unloading was canceled - setTimeout(() => activeElement.focus()); - } - if (editor.dirty.isDirty()) { - // neither confirm() nor custom messages work in modern browsers but just in case - e.returnValue = t('styleChangesNotSaved'); - } -}); - -//#endregion -//#region editor methods - -function EditorMethods() { - const toc = []; - const {dirty, regexps} = editor; - const elTest = $('#testRE'); - let {style} = editor; - let wasDirty = false; - - elTest.hidden = !style.sections.some(({regexps: r}) => r && r.length); - elTest.onclick = () => require([ - '/edit/regexp-tester.css', - '/edit/regexp-tester', /* global regexpTester */ - ], () => regexpTester.toggle(true)); - - Object.defineProperties(editor, { - style: { - get: () => style, - set: val => (style = val), - }, - }); - - /** @namespace Editor */ - Object.assign(editor, { - - applyScrollInfo(cm, si = (editor.scrollInfo.cms || [])[0]) { - if (si && si.sel) { - const bmOpts = {sublimeBookmark: true, clearWhenEmpty: false}; // copied from sublime.js - const bms = cm.state.sublimeBookmarks = []; - for (const b of si.bookmarks) bms.push(cm.markText(b.from, b.to, bmOpts)); - cm.setSelections(...si.sel, {scroll: false}); - Object.assign(cm.display.scroller, si.scroll); // for source editor - Object.assign(cm.doc, si.scroll); // for sectioned editor - } - }, - - makeScrollInfo() { - return { - scrollY: window.scrollY, - cms: editor.getEditors().map(cm => /** @namespace EditorScrollInfo */({ - bookmarks: (cm.state.sublimeBookmarks || []).map(b => b.find()), - focus: cm.hasFocus(), - height: cm.display.wrapper.style.height.replace('100vh', ''), - parentHeight: cm.display.wrapper.parentElement.offsetHeight, - scroll: mapObj(cm.doc, null, ['scrollLeft', 'scrollTop']), - sel: [cm.doc.sel.ranges, cm.doc.sel.primIndex], - })), - }; - }, - - async save() { - if (dirty.isDirty()) { - editor.saving = true; - await editor.saveImpl(); - } - }, - - toggleRegexp(el, type) { - if (type === 'regexp') { - el.on('input', validateRegexp); - if (regexps.add(el).size === 1) elTest.hidden = false; - } else { - el.setCustomValidity(''); - el.off('input', validateRegexp); - if (regexps.delete(el) && !regexps.size) elTest.hidden = true; - } - }, - - toggleStyle(enabled = !style.enabled) { - $('#enabled').checked = enabled; - editor.updateEnabledness(enabled); - }, - - updateDirty() { - const isDirty = dirty.isDirty(); - if (wasDirty !== isDirty) { - wasDirty = isDirty; - document.body.classList.toggle('dirty', isDirty); - $('#save-button').disabled = !isDirty; - } - editor.updateTitle(); - }, - - updateEnabledness(enabled) { - dirty.modify('enabled', style.enabled, enabled); - style.enabled = enabled; - editor.updateLivePreview(); - }, - - updateName(isUserInput) { - if (!editor) return; - if (isUserInput) { - const {value} = $('#name'); - dirty.modify('name', style[editor.nameTarget] || style.name, value); - style[editor.nameTarget] = value; - } - editor.updateTitle(); - }, - - updateToc(added) { - const {sections} = editor; - if (!toc.el) { - toc.el = $('#toc'); - toc.elDetails = toc.el.closest('details'); - toc.title = $('#toc-title').dataset; - } - let num = 0; for (const sec of sections) num += !sec.removed; - if ((+toc.title.num || 1) !== num) { - if (num > 1) toc.title.num = num; - else delete toc.title.num; - } - if (!toc.elDetails.open) return; - if (!added) added = sections; - const first = sections.indexOf(added[0]); - const elFirst = toc.el.children[first]; - if (first >= 0 && (!added.focus || !elFirst)) { - for (let el = elFirst, i = first; i < sections.length; i++) { - const entry = sections[i].tocEntry; - if (!deepEqual(entry, toc[i])) { - if (!el) el = toc.el.appendChild($create('li', {tabIndex: 0})); - el.tabIndex = entry.removed ? -1 : 0; - toc[i] = Object.assign({}, entry); - const s = el.textContent = clipString(entry.label) || ( - entry.target == null - ? t('appliesToEverything') - : clipString(entry.target) + (entry.numTargets > 1 ? ', ...' : '')); - if (s.length > 30) el.title = s; - } - el = el.nextElementSibling; - } - } - while (toc.length > sections.length) { - toc.el.lastElementChild.remove(); - toc.length--; - } - if (added.focus) { - const cls = 'current'; - const old = $('.' + cls, toc.el); - const el = elFirst || toc.el.children[first]; - if (old && old !== el) old.classList.remove(cls); - el.classList.add(cls); - } - }, - - useSavedStyle(newStyle) { - if (style.id !== newStyle.id) { - history.replaceState({}, '', `?id=${newStyle.id}`); - } - sessionStore.justEditedStyleId = newStyle.id; - Object.assign(style, newStyle); - editor.updateClass(); - editor.updateMeta(); - }, - }); -} - -//#endregion -//#region colorpickerHelper - -(async function colorpickerHelper() { - prefs.subscribe('editor.colorpicker.hotkey', (id, hotkey) => { - CodeMirror.commands.colorpicker = invokeColorpicker; - const extraKeys = CodeMirror.defaults.extraKeys; - for (const key in extraKeys) { - if (extraKeys[key] === 'colorpicker') { - delete extraKeys[key]; - break; - } - } - if (hotkey) { - extraKeys[hotkey] = 'colorpicker'; - } - }); - - prefs.subscribe('editor.colorpicker', (id, enabled) => { - const defaults = CodeMirror.defaults; - const keyName = prefs.get('editor.colorpicker.hotkey'); - defaults.colorpicker = enabled; - if (enabled) { - if (keyName) { - CodeMirror.commands.colorpicker = invokeColorpicker; - defaults.extraKeys = defaults.extraKeys || {}; - defaults.extraKeys[keyName] = 'colorpicker'; - } - defaults.colorpicker = { - tooltip: t('colorpickerTooltip'), - popup: { - tooltipForSwitcher: t('colorpickerSwitchFormatTooltip'), - paletteLine: t('numberedLine'), - paletteHint: t('colorpickerPaletteHint'), - hexUppercase: prefs.get('editor.colorpicker.hexUppercase'), - embedderCallback: state => { - ['hexUppercase', 'color'] - .filter(name => state[name] !== prefs.get('editor.colorpicker.' + name)) - .forEach(name => prefs.set('editor.colorpicker.' + name, state[name])); - }, - get maxHeight() { - return prefs.get('editor.colorpicker.maxHeight'); - }, - set maxHeight(h) { - prefs.set('editor.colorpicker.maxHeight', h); - }, - }, - }; - } else { - if (defaults.extraKeys) { - delete defaults.extraKeys[keyName]; - } - } - cmFactory.globalSetOption('colorpicker', defaults.colorpicker); - }, true); - - function invokeColorpicker(cm) { - cm.state.colorpicker.openPopup(prefs.get('editor.colorpicker.color')); - } -})(); - -//#endregion diff --git a/src/edit/editor-worker.js b/src/edit/editor-worker.js index f1a0e1e742b..7cd48db4832 100644 --- a/src/edit/editor-worker.js +++ b/src/edit/editor-worker.js @@ -1,181 +1,178 @@ -/* global createWorkerApi */// worker-util.js 'use strict'; -(() => { - let sugarss = null; +let sugarss = null; - /** @namespace EditorWorker */ - createWorkerApi({ +/** @namespace EditorWorker */ +createWorkerApi({ - async csslint(code, config) { - require(['/js/csslint/parserlib', '/js/csslint/csslint']); /* global CSSLint */ - return CSSLint - .verify(code, config).messages - .map(m => Object.assign(m, {rule: {id: m.rule.id}})); - }, + async csslint(code, config) { + importScripts('/js/csslint/parserlib', '/js/csslint/csslint'); /* global CSSLint */ + return CSSLint + .verify(code, config).messages + .map(m => Object.assign(m, {rule: {id: m.rule.id}})); + }, - getCssPropsValues() { - require(['/js/csslint/parserlib']); /* global parserlib */ - const { - css: {GlobalKeywords, NamedColors, Parser: {AT}, Properties}, - util: {describeProp}, - } = parserlib; - const COLOR = ''; - const rxColor = RegExp(`${COLOR}|${describeProp(COLOR).replace(/[()|]/g, '\\$&')}|~~~`, 'g'); - const rxNonWord = /(?:<.+?>|[^-\w<(]+\d*)+/g; - const res = {}; - // moving vendor-prefixed props to the end - const cmp = (a, b) => a[0] === '-' && b[0] !== '-' ? 1 : a < b ? -1 : a > b; - for (const [k, v] of Object.entries(Properties)) { - if (v !== -1) res[k] = false; // skipping deprecated props - if (typeof v === 'string') { - let last = ''; - const uniq = []; - // strip definitions of function arguments - const vNoColor = v.replace(rxColor, '~~~'); - const desc = describeProp(vNoColor); - const descNoColors = desc.replace(rxColor, ''); - // add a prefix to functions to group them at the end - const words = descNoColors.replace(/([-\w]+\().*?\)/g, 'z-$1').split(rxNonWord).sort(cmp); - for (let w of words) { - if (w.startsWith('z-')) w = w.slice(2); - if (w !== last) uniq.push(last = w); - } - if (desc !== descNoColors || v !== vNoColor) uniq.push(COLOR); - if (uniq.length) res[k] = uniq; + getCssPropsValues() { + importScripts('/js/csslint/parserlib'); /* global parserlib */ + const { + css: {GlobalKeywords, NamedColors, Parser: {AT}, Properties}, + util: {describeProp}, + } = parserlib; + const COLOR = ''; + const rxColor = RegExp(`${COLOR}|${describeProp(COLOR).replace(/[()|]/g, '\\$&')}|~~~`, 'g'); + const rxNonWord = /(?:<.+?>|[^-\w<(]+\d*)+/g; + const res = {}; + // moving vendor-prefixed props to the end + const cmp = (a, b) => a[0] === '-' && b[0] !== '-' ? 1 : a < b ? -1 : a > b; + for (const [k, v] of Object.entries(Properties)) { + if (v !== -1) res[k] = false; // skipping deprecated props + if (typeof v === 'string') { + let last = ''; + const uniq = []; + // strip definitions of function arguments + const vNoColor = v.replace(rxColor, '~~~'); + const desc = describeProp(vNoColor); + const descNoColors = desc.replace(rxColor, ''); + // add a prefix to functions to group them at the end + const words = descNoColors.replace(/([-\w]+\().*?\)/g, 'z-$1').split(rxNonWord).sort(cmp); + for (let w of words) { + if (w.startsWith('z-')) w = w.slice(2); + if (w !== last) uniq.push(last = w); } + if (desc !== descNoColors || v !== vNoColor) uniq.push(COLOR); + if (uniq.length) res[k] = uniq; } - return { - all: res, - ats: [...Object.keys(AT), 'starting-style'] - .map(k => `@${k === 'document' ? '-moz-' : ''}${k}`) - .sort(), - colors: NamedColors, - global: GlobalKeywords, - }; - }, + } + return { + all: res, + ats: [...Object.keys(AT), 'starting-style'] + .map(k => `@${k === 'document' ? '-moz-' : ''}${k}`) + .sort(), + colors: NamedColors, + global: GlobalKeywords, + }; + }, - getRules(linter) { - return ruleRetriever[linter](); // eslint-disable-line no-use-before-define - }, + getRules(linter) { + return ruleRetriever[linter](); // eslint-disable-line no-use-before-define + }, - metalint(code) { - require(['/js/meta-parser']); /* global metaParser */ - const result = metaParser.lint(code); - // extract needed info - result.errors = result.errors.map(err => ({ - code: err.code, - args: err.args, - message: err.message, - index: err.index, - })); - return result; - }, + metalint(code) { + importScripts('/js/meta-parser'); /* global metaParser */ + const result = metaParser.lint(code); + // extract needed info + result.errors = result.errors.map(err => ({ + code: err.code, + args: err.args, + message: err.message, + index: err.index, + })); + return result; + }, - async stylelint(opts) { - require(['/vendor/stylelint-bundle/stylelint-bundle.min']); /* global stylelint */ - // Stylus-lang allows a trailing ";" but sugarss doesn't, so we monkeypatch it - stylelint.SugarSSParser.prototype.checkSemicolon = ovrCheckSemicolon; - for (const r in opts.config.rules) { - if (!stylelint.rules[r]) delete opts.config.rules[r]; + async stylelint(opts) { + importScripts('/vendor/stylelint-bundle/stylelint-bundle.min'); /* global stylelint */ + // Stylus-lang allows a trailing ";" but sugarss doesn't, so we monkeypatch it + stylelint.SugarSSParser.prototype.checkSemicolon = ovrCheckSemicolon; + for (const r in opts.config.rules) { + if (!stylelint.rules[r]) delete opts.config.rules[r]; + } + for (let pass = 2; --pass >= 0;) { + /* We try sugarss (for indented stylus-lang), then css mode, switching them on failure, + * so that the succeeding syntax will be used next time first. */ + if (opts.mode === 'stylus') { + if (sugarss == null) sugarss = !opts.code.includes('{'); + opts.config.customSyntax = sugarss ? 'sugarss' : ''; } - for (let pass = 2; --pass >= 0;) { - /* We try sugarss (for indented stylus-lang), then css mode, switching them on failure, - * so that the succeeding syntax will be used next time first. */ - if (opts.mode === 'stylus') { - if (sugarss == null) sugarss = !opts.code.includes('{'); - opts.config.customSyntax = sugarss ? 'sugarss' : ''; - } - const res = (await stylelint.lint(opts)).results[0]; - const errors = res.parseErrors.concat(res.warnings); - if (sugarss && pass && errors[0] && - errors[0].text === 'Unnecessary curly bracket (CssSyntaxError)') { - sugarss = !sugarss; - continue; - } - return collectStylelintResults(errors, opts); + const res = (await stylelint.lint(opts)).results[0]; + const errors = res.parseErrors.concat(res.warnings); + if (sugarss && pass && errors[0] && + errors[0].text === 'Unnecessary curly bracket (CssSyntaxError)') { + sugarss = !sugarss; + continue; } - }, - }); + return collectStylelintResults(errors, opts); + } + }, +}); - const ruleRetriever = { +const ruleRetriever = { - csslint() { - require(['/js/csslint/csslint']); - return CSSLint.getRuleList().map(rule => { - const output = {}; - for (const [key, value] of Object.entries(rule)) { - if (typeof value !== 'function') { - output[key] = value; - } + csslint() { + importScripts('/js/csslint/csslint'); + return CSSLint.getRuleList().map(rule => { + const output = {}; + for (const [key, value] of Object.entries(rule)) { + if (typeof value !== 'function') { + output[key] = value; } - return output; - }); - }, + } + return output; + }); + }, - stylelint() { - require(['/vendor/stylelint-bundle/stylelint-bundle.min']); - const options = {}; - const rxPossible = /\bpossible:("(?:[^"]*?)"|\[(?:[^\]]*?)\]|\{(?:[^}]*?)\})/g; - const rxString = /"([-\w\s]{3,}?)"/g; - for (const [id, rule] of Object.entries(stylelint.rules)) { - const ruleCode = `${rule()}`; - const sets = []; - let m, mStr; - while ((m = rxPossible.exec(ruleCode))) { - const possible = m[1]; - const set = []; - while ((mStr = rxString.exec(possible))) { - const s = mStr[1]; - if (s.includes(' ')) { - set.push(...s.split(/\s+/)); - } else { - set.push(s); - } - } - if (possible.includes('ignoreAtRules')) { - set.push('ignoreAtRules'); - } - if (possible.includes('ignoreShorthands')) { - set.push('ignoreShorthands'); - } - if (set.length) { - sets.push(set); + stylelint() { + importScripts('/vendor/stylelint-bundle/stylelint-bundle.min'); + const options = {}; + const rxPossible = /\bpossible:("(?:[^"]*?)"|\[(?:[^\]]*?)\]|\{(?:[^}]*?)\})/g; + const rxString = /"([-\w\s]{3,}?)"/g; + for (const [id, rule] of Object.entries(stylelint.rules)) { + const ruleCode = `${rule()}`; + const sets = []; + let m, mStr; + while ((m = rxPossible.exec(ruleCode))) { + const possible = m[1]; + const set = []; + while ((mStr = rxString.exec(possible))) { + const s = mStr[1]; + if (s.includes(' ')) { + set.push(...s.split(/\s+/)); + } else { + set.push(s); } } - options[id] = sets; + if (possible.includes('ignoreAtRules')) { + set.push('ignoreAtRules'); + } + if (possible.includes('ignoreShorthands')) { + set.push('ignoreShorthands'); + } + if (set.length) { + sets.push(set); + } } - return options; - }, - }; + options[id] = sets; + } + return options; + }, +}; - function collectStylelintResults(messages, {mode}) { - /* We hide nonfatal "//" warnings since we lint with sugarss without applying @preprocessor. - * We can't easily pre-remove "//" comments which may be inside strings, comments, url(), etc. - * And even if we did, it'd be wrong to hide potential bugs in stylus-lang like #1460 */ - const isLess = mode === 'text/x-less'; - const slashCommentAllowed = isLess || mode === 'stylus'; - const res = []; - for (const m of messages) { - const {rule} = m; - const msg = m.text.replace(/^Unexpected\s+/, '').replace(` (${rule})`, ''); - if (slashCommentAllowed && msg.includes('"//"') || - isLess && /^unknown at-rule "@[-\w]+:"/.test(msg) /* LESS variables */) { - continue; - } - const {line: L, column: C} = m; - res.push({ - from: {line: L - 1, ch: C - 1}, - to: {line: (m.endLine || L) - 1, ch: (m.endColumn || C) - 1}, - message: msg[0].toUpperCase() + msg.slice(1), - severity: m.severity, - rule, - }); +function collectStylelintResults(messages, {mode}) { + /* We hide nonfatal "//" warnings since we lint with sugarss without applying @preprocessor. + * We can't easily pre-remove "//" comments which may be inside strings, comments, url(), etc. + * And even if we did, it'd be wrong to hide potential bugs in stylus-lang like #1460 */ + const isLess = mode === 'text/x-less'; + const slashCommentAllowed = isLess || mode === 'stylus'; + const res = []; + for (const m of messages) { + const {rule} = m; + const msg = m.text.replace(/^Unexpected\s+/, '').replace(` (${rule})`, ''); + if (slashCommentAllowed && msg.includes('"//"') || + isLess && /^unknown at-rule "@[-\w]+:"/.test(msg) /* LESS variables */) { + continue; } - return res; + const {line: L, column: C} = m; + res.push({ + from: {line: L - 1, ch: C - 1}, + to: {line: (m.endLine || L) - 1, ch: (m.endColumn || C) - 1}, + message: msg[0].toUpperCase() + msg.slice(1), + severity: m.severity, + rule, + }); } + return res; +} - function ovrCheckSemicolon(tt) { - while (tt.length && tt[tt.length - 1][0] === ';') tt.pop(); - } -})(); +function ovrCheckSemicolon(tt) { + while (tt.length && tt[tt.length - 1][0] === ';') tt.pop(); +} diff --git a/src/edit/editor.js b/src/edit/editor.js index 605d1bbcec4..b3a39aacba3 100644 --- a/src/edit/editor.js +++ b/src/edit/editor.js @@ -2,9 +2,9 @@ import {$, $create} from '/js/dom'; import {t} from '/js/localization'; import * as prefs from '/js/prefs'; import {clipString, debounce, deepEqual, fetchText, mapObj, sessionStore} from '/js/toolbox'; +import CODEMIRROR_THEMES from './codemirror-themes'; import DirtyReporter from './dirty-reporter'; -const CM_THEMES = {}; const dirty = DirtyReporter(); const mqCompact = matchMedia('(max-width: 850px)'); /** @type {Set} */ @@ -123,16 +123,16 @@ const editor = { }, async updateTheme(name) { - const el = $('#cm-theme'); - const { - [name]: css = await fetchText(`/vendor/codemirror/theme/${name}.css`).catch(() => ''), - } = CM_THEMES; - if (!css) { + let css; + if (!CODEMIRROR_THEMES.includes[name]) { + css = ''; name = 'default'; prefs.set('editor.theme', name); + } else { + css = await fetchText(`/vendor/codemirror/theme/${name}.css`); } - el.dataset.theme = name; - el.textContent = css; + $('#cm-theme').dataset.theme = name; + $('#cm-theme').textContent = css; }, updateTitle(isDirty = editor.dirty.isDirty()) { diff --git a/src/edit/embedded-popup.js b/src/edit/embedded-popup.js index e88e0c92e7a..7dfd1802b25 100644 --- a/src/edit/embedded-popup.js +++ b/src/edit/embedded-popup.js @@ -1,10 +1,9 @@ -/* global $ $create $remove getEventKeyName */// dom.js -/* global CodeMirror */ -/* global prefs */ -/* global t */// localization.js -'use strict'; +import {$, $create, $remove, getEventKeyName} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import {extraKeys} from './codemirror-default'; -(() => { +export default function EmbeddedPopup() { const ID = 'popup-iframe'; const SEL = '#' + ID; const URL = chrome.runtime.getManifest().browser_action.default_popup; @@ -24,7 +23,7 @@ t.body(() => { document.body.appendChild(btn); // Adding a dummy command to show in keymap help popup - CodeMirror.defaults.extraKeys[POPUP_HOTKEY] = 'openStylusPopup'; + extraKeys[POPUP_HOTKEY] = 'openStylusPopup'; }); prefs.subscribe('iconset', (_, val) => { @@ -106,4 +105,4 @@ removePopup(); } } -})(); +} diff --git a/src/edit/global-search.js b/src/edit/global-search.js index 9f9d84700cf..0c7f53c6c63 100644 --- a/src/edit/global-search.js +++ b/src/edit/global-search.js @@ -1,15 +1,12 @@ -/* global $ $$ $create $remove setInputValue toggleDataset */// dom.js -/* global CodeMirror */ -/* global chromeLocal */// storage-util.js -/* global colorMimicry */ -/* global debounce stringAsRegExp tryRegExp */// toolbox.js -/* global editor */ -/* global t */// localization.js -'use strict'; - -(() => { - require(['/edit/global-search.css']); - +import colorMimicry from '/js/color/color-mimicry'; +import {$, $$, $create, $remove, setInputValue, toggleDataset} from '/js/dom'; +import {t} from '/js/localization'; +import {chromeLocal} from '/js/storage-util'; +import {debounce, stringAsRegExp, tryRegExp} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import editor from './editor'; + +export default function GlobalSearch() { //region Constants and state const INCREMENTAL_SEARCH_DELAY = 0; @@ -197,7 +194,8 @@ state.replaceHasRefs = /\$[$&`'\d]/.test(state.replaceValue); } const cmFocused = document.activeElement && document.activeElement.closest('.CodeMirror'); - state.activeAppliesTo = $(`.${APPLIES_VALUE_CLASS}:focus, .${APPLIES_VALUE_CLASS}.${TARGET_CLASS}`); + state.activeAppliesTo = + $(`.${APPLIES_VALUE_CLASS}:focus, .${APPLIES_VALUE_CLASS}.${TARGET_CLASS}`); state.cmStart = editor.closestVisible( cmFocused && document.activeElement || state.activeAppliesTo || @@ -206,7 +204,6 @@ state.editors = cmExtra ? [cmExtra.CodeMirror] : editor.getEditors(); } - function doSearch({ reverse = state.reverse, canAdvance = true, @@ -221,7 +218,8 @@ } initState(); const {cmStart} = state; - const {index, found, foundInCode} = state.find && doSearchInEditors({cmStart, canAdvance, inApplies}) || {}; + const {index, found, foundInCode} = + state.find && doSearchInEditors({cmStart, canAdvance, inApplies}) || {}; if (!foundInCode) clearMarker(); if (!found) makeTargetVisible(null); const radiateFrom = foundInCode ? index : state.editors.indexOf(cmStart); @@ -237,7 +235,6 @@ return found; } - function doSearchInEditors({cmStart, canAdvance, inApplies}) { const query = state.rx || state.find; const reverse = state.reverse; @@ -280,7 +277,6 @@ } } - function doSearchInApplies(cm, canAdvance) { if (!state.searchInApplies) return; const inputs = editor.getSearchableInputs(cm); @@ -343,7 +339,6 @@ } } - function doReplaceAll() { initState({initReplace: true}); clearMarker(); @@ -357,7 +352,6 @@ } } - function doReplaceInEditor({cm, pos, all = false}) { const cursor = cm.getSearchCursor(state.rx || state.find, pos, state.cursorOptions); const replace = state.replaceValue; @@ -388,7 +382,6 @@ return found; } - function doUndo() { let undoneSome; saveWindowScrollPos(); @@ -422,7 +415,6 @@ //endregion //region Overlay - function setupOverlay(queue, debounced) { if (!queue.length) { return; @@ -492,7 +484,6 @@ if (!queue.length) debounce.unregister(setupOverlay); } - function tokenize(stream) { this.query.lastIndex = stream.pos; const match = this.query.exec(stream.string); @@ -512,7 +503,6 @@ } } - function annotateScrollbar(cm, query, icase) { getStateSafe(cm).annotate = cm.showMatchesOnScrollbar(query, icase, ANNOTATE_SCROLLBAR_OPTIONS); debounce(showTally); @@ -543,13 +533,11 @@ } } - function dialogShown(type) { return document.body.contains(state.input) && (!type || state.dialog.dataset.type === type); } - function createDialog(type) { state.originalFocus = document.activeElement; state.firstRun = true; @@ -615,7 +603,6 @@ return dialog; } - function createInput(index, name, value) { const input = state[name] = $$('textarea', state.dialog)[index]; if (!input) { @@ -628,7 +615,6 @@ $('[data-action]', input.parentElement)._input = input; } - function destroyDialog({restoreFocus = false} = {}) { state.input = null; $remove(DIALOG_SELECTOR); @@ -642,7 +628,6 @@ } } - function adjustTextareaSize(el) { const oldWidth = parseFloat(el.style.width) || el.clientWidth; const widthHistory = el._widthHistory = el._widthHistory || new Map(); @@ -661,7 +646,8 @@ const dialogRight = state.dialog.getBoundingClientRect().right; const textRight = (state.input2 || state.input).getBoundingClientRect().right; newWidth = Math.min(newWidth, - (window.innerWidth - dialogRightOffset - (dialogRight - textRight)) / (state.input2 ? 2 : 1) - 20); + (window.innerWidth - dialogRightOffset - (dialogRight - textRight)) / + (state.input2 ? 2 : 1) - 20); el.style.width = newWidth + 'px'; } const ovrX = el.scrollWidth > el.clientWidth; @@ -672,7 +658,6 @@ el.style.overflowX = ovrX ? '' : 'hidden'; } - function enableReplaceButtons(enabled) { if (state.dialog && state.dialog.dataset.type === 'replace') { for (const el of $$('[data-action^="replace"]', state.dialog)) { @@ -681,7 +666,6 @@ } } - function enableUndoButton(enabled) { if (state.dialog && state.dialog.dataset.type === 'replace') { for (const el of $$('[data-action="undo"]', state.dialog)) { @@ -690,7 +674,6 @@ } } - function focusUndoButton() { for (const btn of $$('[data-action="undo"]', state.dialog)) { if (getComputedStyle(btn).display !== 'none') { @@ -707,7 +690,6 @@ return cm.state.search || (cm.state.search = {}); } - // determines search start position: // the cursor if it was moved or the last match function getContinuationPos({cm, reverse}) { @@ -715,23 +697,21 @@ const posType = reverse ? 'from' : 'to'; const searchPos = (cmSearchState.searchPos || {})[posType]; const cursorPos = cm.getCursor(posType); - const preferCursor = !searchPos || CodeMirror.cmpPos(cursorPos, cmSearchState.cursorPos[posType]); + const preferCursor = !searchPos || + CodeMirror.cmpPos(cursorPos, cmSearchState.cursorPos[posType]); return preferCursor ? cursorPos : searchPos; } - function getEOF(cm) { const line = cm.doc.size - 1; return {line, ch: cm.getLine(line).length}; } - function getNextEditor(cm, step = 1) { const editors = state.editors; return editors[(editors.indexOf(cm) + step + editors.length) % editors.length]; } - // sets the editor to start the search in // e.g. when the user switched to another editor and invoked a search command function setActiveEditor(cm) { @@ -741,7 +721,6 @@ } } - // adds a class on the editor that contains the active match // instead of focusing it (in order to keep the minidialog focused) function makeTargetVisible(element) { @@ -758,10 +737,10 @@ } } - // scrolls the editor to reveal the match function makeMatchVisible(cm, searchCursor) { - const canFocus = !state.firstRun && (!state.dialog || !state.dialog.contains(document.activeElement)); + const canFocus = !state.firstRun && + (!state.dialog || !state.dialog.contains(document.activeElement)); state.cm = cm; // scroll within the editor const pos = searchCursor.pos; @@ -792,12 +771,10 @@ } } - function clearMarker() { if (state.marker) state.marker.clear(); } - function showTally(num, numApplies) { if (!state.tally) return; if (num === undefined) { @@ -838,7 +815,6 @@ } } - function trimUndoHistory() { const history = state.undoHistory; for (let last; (last = history[history.length - 1]);) { @@ -852,7 +828,6 @@ } } - function focusNoScroll(el) { if (el) { saveWindowScrollPos(); @@ -861,13 +836,11 @@ } } - function saveWindowScrollPos() { state.scrollX = window.scrollX; state.scrollY = window.scrollY; } - function restoreWindowScrollPos({immediately = true} = {}) { if (!immediately) { // run in the next microtask cycle @@ -879,7 +852,6 @@ } } - // produces [i, i+1, i-1, i+2, i-2, i+3, i-3, ...] function radiateArray(arr, focalIndex) { const focus = arr[focalIndex]; @@ -897,7 +869,6 @@ return result; } - function readStorage() { chromeLocal.getValue('editor').then((editor = {}) => { state.find = editor.find || ''; @@ -906,7 +877,6 @@ }); } - function writeStorage() { chromeLocal.getValue('editor').then((editor = {}) => chromeLocal.setValue('editor', Object.assign(editor, { @@ -917,4 +887,4 @@ } //endregion -})(); +} diff --git a/src/edit/index.js b/src/edit/index.js index 8ad6eb47405..2e4d11ddcdc 100644 --- a/src/edit/index.js +++ b/src/edit/index.js @@ -1,4 +1,4 @@ -import {$, $$, $create, important} from '/js/dom'; +import {$, $$} from '/js/dom'; import {t} from '/js/localization'; import * as prefs from '/js/prefs'; import '/css/global.css'; @@ -35,8 +35,10 @@ import '/vendor-overwrites/codemirror-addon/match-highlighter.js'; import '/js/color/color-picker.css'; import './codemirror-default.css'; import './edit.css'; +import './regexp-tester.css'; import './settings.css'; import Autocomplete from './autocomplete'; +import CompactHeader from './compact-header'; import Drafts from './drafts'; import editor from './editor'; import EditorHeader from './editor-header'; @@ -58,18 +60,21 @@ t.body(); styleReady.then(async () => { EditorHeader(); + // TODO: load respective js on demand? await (editor.isUsercss ? SourceEditor : SectionsEditor)(); - editor.dirty.onChange(editor.updateDirty); prefs.subscribe('editor.linter', () => linterMan.run()); - + Autocomplete(); + CompactHeader(); + Drafts(); + GlobalSearch(); // enabling after init to prevent flash of validation failure on an empty name $('#name').required = !editor.isUsercss; $('#save-button').onclick = editor.save; $('#cancel-button').onclick = editor.cancel; $('#lint-help').onclick = showLintHelp; $('#testRE').hidden = !editor.style.sections.some(({regexps: r}) => r && r.length); - $('#testRE').onclick = () => require(['/edit/regexp-tester.css'], () => regexpTester.toggle(true)); + $('#testRE').onclick = () => regexpTester.toggle(true); const elSec = $('#sections-list'); const elToc = $('#toc'); const moDetails = new MutationObserver(([{target: sec}]) => { @@ -89,52 +94,4 @@ styleReady.then(async () => { } elToc.onclick = e => editor.jumpToEditor([].indexOf.call(elToc.children, e.target)); - - Autocomplete(); - Drafts(); - GlobalSearch(); -}); - -styleReady.then(async () => { - // Set up mini-header on scroll - const {isUsercss} = editor; - const el = $create({ - style: important(` - top: 0; - height: 1px; - position: absolute; - visibility: hidden; - `), - }); - const scroller = isUsercss ? $('.CodeMirror-scroll') : document.body; - const xoRoot = isUsercss ? scroller : undefined; - const xo = new IntersectionObserver(onScrolled, {root: xoRoot}); - const elInfo = $('h1 a'); - scroller.appendChild(el); - onCompactToggled(editor.mqCompact); - editor.mqCompact.on('change', onCompactToggled); - - /** @param {MediaQueryList} mq */ - function onCompactToggled(mq) { - for (const el of $$('details[data-pref]')) { - el.open = mq.matches ? false : - el.classList.contains('ignore-pref') ? el.open : - prefs.get(el.dataset.pref); - } - if (mq.matches) { - xo.observe(el); - $('#basic-info-name').after(elInfo); - } else { - xo.disconnect(); - $('h1').append(elInfo); - } - } - - /** @param {IntersectionObserverEntry[]} entries */ - function onScrolled(entries) { - const h = $('#header'); - const sticky = !entries.pop().intersectionRatio; - if (!isUsercss) scroller.style.paddingTop = sticky ? h.offsetHeight + 'px' : ''; - h.classList.toggle('sticky', sticky); - } }); diff --git a/src/edit/linter-dialogs.js b/src/edit/linter-dialogs.js index 316e5e082e2..cf43a30fcdf 100644 --- a/src/edit/linter-dialogs.js +++ b/src/edit/linter-dialogs.js @@ -1,263 +1,257 @@ -/* global $ $create $createLink messageBoxProxy */// dom.js -/* global chromeSync */// storage-util.js -/* global editor */ -/* global helpPopup showCodeMirrorPopup */// util.js -/* global linterMan */ -/* global t */// localization.js -/* global tryJSONparse */// toolbox.js -'use strict'; +import messageBox from '/js/dlg/message-box'; +import {$, $create, $createLink} from '/js/dom'; +import {t} from '/js/localization'; +import {chromeSync} from '/js/storage-util'; +import {tryJSONparse} from '/js/toolbox'; +import editor from './editor'; +import linterMan from './linter-manager'; +import {helpPopup, showCodeMirrorPopup} from './util'; -(() => { - /** @type {{csslint:{}, stylelint:{}}} */ - const RULES = {}; - const KNOWN_RULES = {}; - const defaultConfig = {}; - let cm; - let knownRules; - let isStylelint; - let linter; - let popup; +/** @type {{csslint:{}, stylelint:{}}} */ +const RULES = {}; +const KNOWN_RULES = {}; +const defaultConfig = {}; +let cm; +let knownRules; +let isStylelint; +let linter; +let popup; - linterMan.showLintConfig = async () => { - linter = await getLinter(); - if (!linter) { - return; - } - await require([ - '/vendor/codemirror/mode/javascript/javascript', - '/vendor/codemirror/addon/lint/json-lint', - '/vendor/jsonlint/jsonlint', - ]); - const config = await chromeSync.getLZValue(chromeSync.LZ_KEY[linter]); - const title = t('linterConfigPopupTitle', isStylelint ? 'Stylelint' : 'CSSLint'); - const activeRules = new Set(getActiveRules()); - isStylelint = linter === 'stylelint'; - knownRules = KNOWN_RULES[linter] || ( - KNOWN_RULES[linter] = new Set(( - isStylelint - ? Object.keys(RULES[linter]) - : RULES[linter].map(r => r.id) - ).sort())); - for (let cfg of [ - config, - !defaultConfig[linter] && linterMan.DEFAULTS[linter], - ].filter(Boolean)) { - const missingRules = new Set(knownRules); - cfg = isStylelint ? cfg.rules : cfg; - for (const id in cfg) { - if (cfg[id] && knownRules.has(id)) { - missingRules.delete(id); - } else if (/^[a-z]+(-[a-z]+)*$/.test(id)) { - // Deleting unknown rules that look like a valid id but allow unusual ids for user comments - delete cfg[id]; - } - } - for (const id of missingRules) { - cfg[id] = isStylelint ? false : 0; +export async function showLintConfig() { + linter = await getLinter(); + if (!linter) { + return; + } + await import('/js/jsonlint-bundle'); + const config = await chromeSync.getLZValue(chromeSync.LZ_KEY[linter]); + const title = t('linterConfigPopupTitle', isStylelint ? 'Stylelint' : 'CSSLint'); + const activeRules = new Set(getActiveRules()); + isStylelint = linter === 'stylelint'; + knownRules = KNOWN_RULES[linter] || ( + KNOWN_RULES[linter] = new Set(( + isStylelint + ? Object.keys(RULES[linter]) + : RULES[linter].map(r => r.id) + ).sort())); + for (let cfg of [ + config, + !defaultConfig[linter] && linterMan.DEFAULTS[linter], + ].filter(Boolean)) { + const missingRules = new Set(knownRules); + cfg = isStylelint ? cfg.rules : cfg; + for (const id in cfg) { + if (cfg[id] && knownRules.has(id)) { + missingRules.delete(id); + } else if (/^[a-z]+(-[a-z]+)*$/.test(id)) { + // Deleting unknown rules that look like a valid id but allow unusual ids for user comments + delete cfg[id]; } } - defaultConfig[linter] = stringifyConfig(linterMan.DEFAULTS[linter]); - popup = showCodeMirrorPopup(title, null, { - extraKeys: {'Ctrl-Enter': onConfigSave}, - hintOptions: {hint}, - lint: true, - mode: 'application/json', - value: config ? stringifyConfig(config) : defaultConfig[linter], - }); - popup._contents.appendChild( - $create('div', [ - $create('p', [ - $createLink( - isStylelint - ? 'https://stylelint.io/user-guide/rules/' - : 'https://github.com/CSSLint/csslint/wiki/Rules-by-ID', - t('linterRulesLink')), - linter === 'csslint' ? ' ' + t('linterCSSLintSettings') : '', - ]), - $create('.buttons', [ - $create('button.save', {onclick: onConfigSave, title: 'Ctrl-Enter'}, - t('styleSaveLabel')), - $create('button.cancel', {onclick: onConfigCancel}, t('confirmClose')), - $create('button.reset', {onclick: onConfigReset, title: t('linterResetMessage')}, - t('genericResetLabel')), - ]), - ])); - cm = popup.codebox; - cm.focus(); - cm.addOverlay({ - token(stream) { - const t = stream.baseToken(); - if (t && t.type === 'string property') { - const id = stream.string.substr(stream.pos + 1, t.size - 2); - if (knownRules.has(id)) { - stream.pos += t.size; - return 'string-2 known-linter-rule' + (activeRules.has(id) ? ' active-linter-rule' : ''); - } - } - stream.pos += t ? t.size : 1e9; - }, - }); - cm.on('changes', updateConfigButtons); - updateConfigButtons(); - popup.onClose.add(onConfigClose); - }; - - linterMan.showLintHelp = async () => { - const linter = await getLinter(); - const baseUrl = linter === 'stylelint' - ? 'https://stylelint.io/user-guide/rules/' - : ''; - let headerLink, template; - if (linter === 'csslint') { - headerLink = $createLink('https://github.com/CSSLint/csslint/wiki/Rules', 'CSSLint'); - template = ruleID => { - const rule = RULES.csslint.find(rule => rule.id === ruleID); - return rule && - $create('li', [ - $create('b', ruleID + ': '), - rule.url ? $createLink(rule.url, rule.name) : $create('span', `"${rule.name}"`), - $create('p', rule.desc), - ]); - }; - } else { - headerLink = $createLink(baseUrl, 'stylelint'); - template = rule => - $create('li', - rule === 'CssSyntaxError' ? rule : $createLink(baseUrl + rule, rule)); + for (const id of missingRules) { + cfg[id] = isStylelint ? false : 0; } - const header = t('linterIssuesHelp', '\x01').split('\x01'); - helpPopup.show(t('linterIssues'), - $create([ - header[0], headerLink, header[1], - $create('ul.rules', getActiveRules().map(template)), - $create('button', {onclick: linterMan.showLintConfig}, t('configureStyle')), - ])); - }; + } + defaultConfig[linter] = stringifyConfig(linterMan.DEFAULTS[linter]); + popup = showCodeMirrorPopup(title, null, { + extraKeys: {'Ctrl-Enter': onConfigSave}, + hintOptions: {hint}, + lint: true, + mode: 'application/json', + value: config ? stringifyConfig(config) : defaultConfig[linter], + }); + popup._contents.appendChild( + $create('div', [ + $create('p', [ + $createLink( + isStylelint + ? 'https://stylelint.io/user-guide/rules/' + : 'https://github.com/CSSLint/csslint/wiki/Rules-by-ID', + t('linterRulesLink')), + linter === 'csslint' ? ' ' + t('linterCSSLintSettings') : '', + ]), + $create('.buttons', [ + $create('button.save', {onclick: onConfigSave, title: 'Ctrl-Enter'}, + t('styleSaveLabel')), + $create('button.cancel', {onclick: onConfigCancel}, t('confirmClose')), + $create('button.reset', {onclick: onConfigReset, title: t('linterResetMessage')}, + t('genericResetLabel')), + ]), + ])); + cm = popup.codebox; + cm.focus(); + cm.addOverlay({ + token(stream) { + const t = stream.baseToken(); + if (t && t.type === 'string property') { + const id = stream.string.substr(stream.pos + 1, t.size - 2); + if (knownRules.has(id)) { + stream.pos += t.size; + return 'string-2 known-linter-rule' + (activeRules.has(id) ? ' active-linter-rule' : ''); + } + } + stream.pos += t ? t.size : 1e9; + }, + }); + cm.on('changes', updateConfigButtons); + updateConfigButtons(); + popup.onClose.add(onConfigClose); +} - function getActiveRules() { - const all = [...linterMan.getIssues()].map(issue => issue.rule); - const uniq = new Set(all); - return [...uniq]; +export async function showLintHelp() { + const linter = await getLinter(); + const baseUrl = linter === 'stylelint' + ? 'https://stylelint.io/user-guide/rules/' + : ''; + let headerLink, template; + if (linter === 'csslint') { + headerLink = $createLink('https://github.com/CSSLint/csslint/wiki/Rules', 'CSSLint'); + template = ruleID => { + const rule = RULES.csslint.find(rule => rule.id === ruleID); + return rule && + $create('li', [ + $create('b', ruleID + ': '), + rule.url ? $createLink(rule.url, rule.name) : $create('span', `"${rule.name}"`), + $create('p', rule.desc), + ]); + }; + } else { + headerLink = $createLink(baseUrl, 'stylelint'); + template = rule => + $create('li', + rule === 'CssSyntaxError' ? rule : $createLink(baseUrl + rule, rule)); } + const header = t('linterIssuesHelp', '\x01').split('\x01'); + helpPopup.show(t('linterIssues'), + $create([ + header[0], headerLink, header[1], + $create('ul.rules', getActiveRules().map(template)), + $create('button', {onclick: showLintConfig}, t('configureStyle')), + ])); +} - function getLexicalDepth(lexicalState) { - let depth = 0; - while ((lexicalState = lexicalState.prev)) { - depth++; - } - return depth; +function getActiveRules() { + const all = [...linterMan.getIssues()].map(issue => issue.rule); + const uniq = new Set(all); + return [...uniq]; +} + +function getLexicalDepth(lexicalState) { + let depth = 0; + while ((lexicalState = lexicalState.prev)) { + depth++; } + return depth; +} - async function getLinter() { - const val = editor.getCurrentLinter(); - if (val && !RULES[val]) { - RULES[val] = await linterMan.worker.getRules(val); - } - return val; +async function getLinter() { + const val = editor.getCurrentLinter(); + if (val && !RULES[val]) { + RULES[val] = await linterMan.worker.getRules(val); } + return val; +} - function hint(cm) { - const rules = RULES[linter]; - let ruleIds, options; - if (isStylelint) { - ruleIds = Object.keys(rules); - options = rules; - } else { - ruleIds = rules.map(r => r.id); - options = {}; - } - const cursor = cm.getCursor(); - const {start, end, string, type, state: {lexical}} = cm.getTokenAt(cursor); - const {line, ch} = cursor; +function hint(cm) { + const rules = RULES[linter]; + let ruleIds, options; + if (isStylelint) { + ruleIds = Object.keys(rules); + options = rules; + } else { + ruleIds = rules.map(r => r.id); + options = {}; + } + const cursor = cm.getCursor(); + const {start, end, string, type, state: {lexical}} = cm.getTokenAt(cursor); + const {line, ch} = cursor; - const quoted = string.startsWith('"'); - const leftPart = string.slice(quoted ? 1 : 0, ch - start).trim(); - const depth = getLexicalDepth(lexical); + const quoted = string.startsWith('"'); + const leftPart = string.slice(quoted ? 1 : 0, ch - start).trim(); + const depth = getLexicalDepth(lexical); - const search = cm.getSearchCursor(/"([-\w]+)"/, {line, ch: start - 1}); - let [, prevWord] = search.find(true) || []; - let words = []; + const search = cm.getSearchCursor(/"([-\w]+)"/, {line, ch: start - 1}); + let [, prevWord] = search.find(true) || []; + let words = []; - if (depth === 1 && isStylelint) { - words = quoted ? ['rules'] : []; - } else if ((depth === 1 || depth === 2) && type && type.includes('property')) { - words = ruleIds; - } else if (depth === 2 || depth === 3 && lexical.type === ']') { - words = !quoted ? ['true', 'false', 'null'] : - ruleIds.includes(prevWord) && (options[prevWord] || [])[0] || []; - } else if (depth === 4 && prevWord === 'severity') { - words = ['error', 'warning']; - } else if (depth === 4) { - words = ['ignore', 'ignoreAtRules', 'except', 'severity']; - } else if (depth === 5 && lexical.type === ']' && quoted) { - while (prevWord && !ruleIds.includes(prevWord)) { - prevWord = (search.find(true) || [])[1]; - } - words = (options[prevWord] || []).slice(-1)[0] || ruleIds; + if (depth === 1 && isStylelint) { + words = quoted ? ['rules'] : []; + } else if ((depth === 1 || depth === 2) && type && type.includes('property')) { + words = ruleIds; + } else if (depth === 2 || depth === 3 && lexical.type === ']') { + words = !quoted ? ['true', 'false', 'null'] : + ruleIds.includes(prevWord) && (options[prevWord] || [])[0] || []; + } else if (depth === 4 && prevWord === 'severity') { + words = ['error', 'warning']; + } else if (depth === 4) { + words = ['ignore', 'ignoreAtRules', 'except', 'severity']; + } else if (depth === 5 && lexical.type === ']' && quoted) { + while (prevWord && !ruleIds.includes(prevWord)) { + prevWord = (search.find(true) || [])[1]; } - return { - list: words.filter(word => word.startsWith(leftPart)), - from: {line, ch: start + (quoted ? 1 : 0)}, - to: {line, ch: string.endsWith('"') ? end - 1 : end}, - }; + words = (options[prevWord] || []).slice(-1)[0] || ruleIds; } + return { + list: words.filter(word => word.startsWith(leftPart)), + from: {line, ch: start + (quoted ? 1 : 0)}, + to: {line, ch: string.endsWith('"') ? end - 1 : end}, + }; +} - function onConfigCancel() { - helpPopup.close(); - editor.closestVisible().focus(); - } +function onConfigCancel() { + helpPopup.close(); + editor.closestVisible().focus(); +} - function onConfigClose() { - cm = null; - } +function onConfigClose() { + cm = null; +} + +function onConfigReset(event) { + event.preventDefault(); + cm.setValue(defaultConfig[linter]); + cm.focus(); + updateConfigButtons(); +} - function onConfigReset(event) { +async function onConfigSave(event) { + if (event instanceof Event) { event.preventDefault(); - cm.setValue(defaultConfig[linter]); - cm.focus(); - updateConfigButtons(); } - - async function onConfigSave(event) { - if (event instanceof Event) { - event.preventDefault(); - } - const json = tryJSONparse(cm.getValue()); - if (!json) { - showLinterErrorMessage(linter, t('linterJSONError'), popup); - cm.focus(); - return; - } - const cfg = isStylelint ? json.rules : json; - for (const id in cfg) { - if (!cfg[id]) delete cfg[id]; - } - chromeSync.setLZValue(chromeSync.LZ_KEY[linter], json); - cm.markClean(); + const json = tryJSONparse(cm.getValue()); + if (!json) { + showLinterErrorMessage(linter, t('linterJSONError'), popup); cm.focus(); - updateConfigButtons(); + return; } - - function stringifyConfig(config) { - return JSON.stringify(config, null, 2) - .replace(/,\n\s+{\n\s+("severity":\s"\w+")\n\s+}/g, ', {$1}'); + const cfg = isStylelint ? json.rules : json; + for (const id in cfg) { + if (!cfg[id]) delete cfg[id]; } + chromeSync.setLZValue(chromeSync.LZ_KEY[linter], json); + cm.markClean(); + cm.focus(); + updateConfigButtons(); +} - async function showLinterErrorMessage(title, contents, popup) { - await messageBoxProxy.show({ - title, - contents, - className: 'danger center lint-config', - buttons: [t('confirmOK')], - }); - if (popup && popup.codebox) { - popup.codebox.focus(); - } - } +function stringifyConfig(config) { + return JSON.stringify(config, null, 2) + .replace(/,\n\s+{\n\s+("severity":\s"\w+")\n\s+}/g, ', {$1}'); +} - function updateConfigButtons() { - $('.save', popup).disabled = cm.isClean(); - $('.reset', popup).disabled = cm.getValue() === defaultConfig[linter]; - $('.cancel', popup).textContent = t(cm.isClean() ? 'confirmClose' : 'confirmCancel'); +async function showLinterErrorMessage(title, contents, popup) { + await messageBox.show({ + title, + contents, + className: 'danger center lint-config', + buttons: [t('confirmOK')], + }); + if (popup && popup.codebox) { + popup.codebox.focus(); } -})(); +} + +function updateConfigButtons() { + $('.save', popup).disabled = cm.isClean(); + $('.reset', popup).disabled = cm.getValue() === defaultConfig[linter]; + $('.cancel', popup).textContent = t(cm.isClean() ? 'confirmClose' : 'confirmCancel'); +} diff --git a/src/edit/linter-manager.js b/src/edit/linter-manager.js index 442a28a6db8..efc24b022af 100644 --- a/src/edit/linter-manager.js +++ b/src/edit/linter-manager.js @@ -1,13 +1,13 @@ -/* global $ $create */// dom.js -/* global chromeSync */// storage-util.js -/* global clipString */// util.js -/* global createWorker */// worker-util.js -/* global editor */ -/* global prefs */ -'use strict'; +import {$, $create} from '/js/dom'; +import * as prefs from '/js/prefs'; +import {chromeSync} from '/js/storage-util'; +import {clipString} from '/js/toolbox'; +import createWorker from '/js/worker-host'; +import editor from './editor'; //#region linterMan +// TODO: export directly const linterMan = (() => { const cms = new Map(); const linters = []; @@ -358,3 +358,5 @@ linterMan.DEFAULTS = { })(); //#endregion + +export default linterMan; diff --git a/src/edit/live-preview.js b/src/edit/live-preview.js index 226b3dadcee..f02abbe087f 100644 --- a/src/edit/live-preview.js +++ b/src/edit/live-preview.js @@ -65,7 +65,8 @@ async function updatePreviewer(data) { ? {line: err.line - shift, ch: err.column - 1} : err.index; if (Array.isArray(err)) { - err = err.map((e, a, b) => !(a = e.message) ? e : ((b = e.context)) ? `${a} in ${b}` : a).join('\n'); + err = err.map((e, a, b) => !(a = e.message) ? e : ((b = e.context)) ? `${a} in ${b}` : a) + .join('\n'); } else { err = err.message || `${err}`; } diff --git a/src/edit/moz-section-finder.js b/src/edit/moz-section-finder.js index b0ec31ce3b9..7fb8bf4d773 100644 --- a/src/edit/moz-section-finder.js +++ b/src/edit/moz-section-finder.js @@ -1,10 +1,8 @@ -/* global CodeMirror */ -/* global deepEqual */// toolbox.js -/* global trimCommentLabel */// util.js -'use strict'; +import {deepEqual} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import {trimCommentLabel} from './util'; -/* exported MozSectionFinder */ -function MozSectionFinder(cm) { +export default function MozSectionFinder(cm) { const KEY = 'MozSectionFinder'; const MOZ_DOC_LEN = '@-moz-document'.length; const rxDOC = /@-moz-document(\s+|$)/ig; diff --git a/src/edit/moz-section-widget.js b/src/edit/moz-section-widget.js index 47572704ecc..89e7aea0c78 100644 --- a/src/edit/moz-section-widget.js +++ b/src/edit/moz-section-widget.js @@ -1,14 +1,13 @@ -/* global $ $create messageBoxProxy */// dom.js -/* global CodeMirror */ -/* global MozSectionFinder */ -/* global colorMimicry */ -/* global editor */ -/* global msg */ -/* global t */// localization.js -'use strict'; +import colorMimicry from '/js/color/color-mimicry'; +import messageBox from '/js/dlg/message-box'; +import {$, $create} from '/js/dom'; +import {t} from '/js/localization'; +import * as msg from '/js/msg'; +import CodeMirror from 'codemirror'; +import editor from './editor'; +import MozSectionFinder from './moz-section-finder'; -/* exported MozSectionWidget */ -function MozSectionWidget(cm, finder = MozSectionFinder(cm)) { +export default function MozSectionWidget(cm, finder = MozSectionFinder(cm)) { let TPL, EVENTS, CLICK_ROUTE; const KEY = 'MozSectionWidget'; const C_CONTAINER = '.applies-to'; @@ -63,7 +62,7 @@ function MozSectionWidget(cm, finder = MozSectionFinder(cm)) { '.remove-applies-to'(elItem, func) { const funcs = getFuncsFor(elItem); if (funcs.length < 2) { - messageBoxProxy.show({ + messageBox.show({ contents: t('appliesRemoveError'), buttons: [t('confirmClose')], }); @@ -192,7 +191,8 @@ function MozSectionWidget(cm, finder = MozSectionFinder(cm)) { const fore = preferLine ? color.line.fore : color.wrapper.fore; const border = fore.replace(/[\d.]+(?=\))/, MIN_LUMA_DIFF / 2); - const borderStyleForced = `1px ${hasBorder ? color.gutter.style.borderRightStyle : 'solid'} ${border}`; + const borderStyleForced = + `1px ${hasBorder ? color.gutter.style.borderRightStyle : 'solid'} ${border}`; actualStyle.textContent = ` ${C_CONTAINER} { @@ -448,5 +448,4 @@ function MozSectionWidget(cm, finder = MozSectionFinder(cm)) { function setProp(obj, name, value) { return Object.defineProperty(obj, name, {value, configurable: true}); } - } diff --git a/src/edit/regexp-tester.js b/src/edit/regexp-tester.js index 8ae99c288b2..6f656e73362 100644 --- a/src/edit/regexp-tester.js +++ b/src/edit/regexp-tester.js @@ -1,209 +1,204 @@ -/* global API */// msg.js -/* global $create */// dom.js -/* global URLS tryRegExp */// toolbox.js -/* global editor */ -/* global helpPopup */// util.js -/* global t */// localization.js -'use strict'; +import browser from '/js/browser'; +import {$create} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import {tryRegExp, URLS} from '/js/toolbox'; +import editor from './editor'; +import {helpPopup} from './util'; -const regexpTester = (() => { - const OWN_ICON = chrome.runtime.getManifest().icons['16']; - const cachedRegexps = new Map(); - const inputs = editor.regexps; - const observe = (el, on) => el[on ? 'on' : 'off']('input', regexpTester.update); - let isWatching = false; - let popup; - let note; +const OWN_ICON = chrome.runtime.getManifest().icons['16']; +const cachedRegexps = new Map(); +const inputs = editor.regexps; +const observe = (el, on) => el[on ? 'on' : 'off']('input', update); +let isWatching = false; +let popup; +let note; - ['add', 'delete'].forEach((key, i) => { - const fn = inputs[key]; - inputs[key] = el => { - const res = fn.call(inputs, el); - if (isWatching) { - observe(el, !i); - regexpTester.update(); - } - return res; - }; - }); +['add', 'delete'].forEach((key, i) => { + const fn = inputs[key]; + inputs[key] = el => { + const res = fn.call(inputs, el); + if (isWatching) { + observe(el, !i); + update(); + } + return res; + }; +}); - return { +export function toggle(state = !popup) { + if (state && !popup) { + if (!isWatching) { + isWatching = true; + chrome.tabs.onRemoved.addListener(onTabRemoved); + chrome.tabs.onUpdated.addListener(onTabUpdated); + for (const el of inputs) observe(el, true); + } + popup = helpPopup.show(t('styleRegexpTestTitle'), ' ', {className: 'regexp-report'}); + popup.onClose.add(() => toggle(false)); + update(); + } else if (!state && popup) { + unwatch(); + popup._close.click(); + popup = null; + } +} - toggle(state = !popup) { - if (state && !popup) { - if (!isWatching) { - isWatching = true; - chrome.tabs.onRemoved.addListener(onTabRemoved); - chrome.tabs.onUpdated.addListener(onTabUpdated); - for (const el of inputs) observe(el, true); +export async function update() { + if (!popup) { + unwatch(); + return; + } + const regexps = new Map(); + const ael = document.activeElement; + for (const el of inputs) { + const text = el.value; + const old = regexps.get(text); + const rxData = old || Object.assign({text}, cachedRegexps.get(text)); + if (!rxData.urls) { + cachedRegexps.set(text, Object.assign(rxData, { + // imitate buggy Stylish-for-chrome + rx: tryRegExp('^' + text + '$'), + urls: new Map(), + })); + } + if (!old || el === ael) rxData.el = el; + if (!old) regexps.set(text, rxData); + } + const getMatchInfo = m => m && {text: m[0], pos: m.index}; + const tabs = await browser.tabs.query({}); + const supported = tabs.map(tab => tab.pendingUrl || tab.url).filter(URLS.supported); + const unique = [...new Set(supported).values()]; + for (const rxData of regexps.values()) { + const {rx, urls} = rxData; + if (rx) { + const urlsNow = new Map(); + for (const url of unique) { + const match = urls.get(url) || getMatchInfo(url.match(rx)); + if (match) { + urlsNow.set(url, match); } - popup = helpPopup.show(t('styleRegexpTestTitle'), ' ', {className: 'regexp-report'}); - popup.onClose.add(() => regexpTester.toggle(false)); - regexpTester.update(); - } else if (!state && popup) { - unwatch(); - popup._close.click(); - popup = null; } + rxData.urls = urlsNow; + } + } + const stats = { + full: {data: [], label: t('styleRegexpTestFull')}, + partial: { + data: [], label: [ + t('styleRegexpTestPartial'), + t.template.regexpTestPartial.cloneNode(true), + ], }, - - async update() { - if (!popup) { - unwatch(); - return; - } - const regexps = new Map(); - const ael = document.activeElement; - for (const el of inputs) { - const text = el.value; - const old = regexps.get(text); - const rxData = old || Object.assign({text}, cachedRegexps.get(text)); - if (!rxData.urls) { - cachedRegexps.set(text, Object.assign(rxData, { - // imitate buggy Stylish-for-chrome - rx: tryRegExp('^' + text + '$'), - urls: new Map(), - })); - } - if (!old || el === ael) rxData.el = el; - if (!old) regexps.set(text, rxData); - } - const getMatchInfo = m => m && {text: m[0], pos: m.index}; - const tabs = await browser.tabs.query({}); - const supported = tabs.map(tab => tab.pendingUrl || tab.url).filter(URLS.supported); - const unique = [...new Set(supported).values()]; - for (const rxData of regexps.values()) { - const {rx, urls} = rxData; - if (rx) { - const urlsNow = new Map(); - for (const url of unique) { - const match = urls.get(url) || getMatchInfo(url.match(rx)); - if (match) { - urlsNow.set(url, match); - } - } - rxData.urls = urlsNow; - } - } - const stats = { - full: {data: [], label: t('styleRegexpTestFull')}, - partial: { - data: [], label: [ - t('styleRegexpTestPartial'), - t.template.regexpTestPartial.cloneNode(true), - ], - }, - none: {data: [], label: t('styleRegexpTestNone')}, - invalid: {data: [], label: t('styleRegexpTestInvalid')}, - }; - // collect stats - for (const {el, text, rx, urls} of regexps.values()) { - if (!rx) { - stats.invalid.data.push({el, text}); - continue; - } - if (!urls.size) { - stats.none.data.push({el, text}); - continue; - } - const full = []; - const partial = []; - for (const [url, match] of urls.entries()) { - const faviconUrl = url.startsWith(URLS.ownOrigin) - ? OWN_ICON - : URLS.favicon(new URL(url).hostname); - const icon = $create('img', {src: faviconUrl}); - if (match.text.length === url.length) { - full.push($create('a', {tabIndex: 0}, [ - icon, - url, - ])); - } else { - partial.push($create('a', {tabIndex: 0}, [ - icon, - url.substr(0, match.pos), - $create('mark', match.text), - url.substr(match.pos + match.text.length), - ])); - } - } - if (full.length) { - stats.full.data.push({el, text, urls: full}); - } - if (partial.length) { - stats.partial.data.push({el, text, urls: partial}); - } - } - // render stats - const report = $create('div'); - for (const type in stats) { - // top level groups: full, partial, none, invalid - const {label, data} = stats[type]; - if (!data.length) { - continue; - } - const h3 = $create('h3', {'data-num': data.length}, label); - const block = report.appendChild( - $create('details', { - 'data-type': type, - 'open': !report.firstChild, - }, $create('summary', h3))); - // 2nd level: regexp text - for (const {el, text, urls} of data) { - if (urls) { - // type is partial or full - block.appendChild( - $create('article', [ - $create('h4', {_source: el}, text), - ...urls, - ])); - } else { - // type is none or invalid - block.appendChild($create('a', {tabIndex: 0, _source: el}, text)); - } - } + none: {data: [], label: t('styleRegexpTestNone')}, + invalid: {data: [], label: t('styleRegexpTestInvalid')}, + }; + // collect stats + for (const {el, text, rx, urls} of regexps.values()) { + if (!rx) { + stats.invalid.data.push({el, text}); + continue; + } + if (!urls.size) { + stats.none.data.push({el, text}); + continue; + } + const full = []; + const partial = []; + for (const [url, match] of urls.entries()) { + const faviconUrl = url.startsWith(URLS.ownOrigin) + ? OWN_ICON + : URLS.favicon(new URL(url).hostname); + const icon = $create('img', {src: faviconUrl}); + if (match.text.length === url.length) { + full.push($create('a', {tabIndex: 0}, [ + icon, + url, + ])); + } else { + partial.push($create('a', {tabIndex: 0}, [ + icon, + url.substr(0, match.pos), + $create('mark', match.text), + url.substr(match.pos + match.text.length), + ])); } - if (!note) { - note = $create('div.regexp-report-note', - `${t('styleRegexpTestNoteStar')} ${t('styleRegexpTestNote')}` - .split(/(<[^>]+>|\\+)/) - .map((s, i) => i % 2 ? $create('code', s[0] === '<' ? s.slice(1, -1) : s) : s)); + } + if (full.length) { + stats.full.data.push({el, text, urls: full}); + } + if (partial.length) { + stats.partial.data.push({el, text, urls: partial}); + } + } + // render stats + const report = $create('div'); + for (const type in stats) { + // top level groups: full, partial, none, invalid + const {label, data} = stats[type]; + if (!data.length) { + continue; + } + const h3 = $create('h3', {'data-num': data.length}, label); + const block = report.appendChild( + $create('details', { + 'data-type': type, + 'open': !report.firstChild, + }, $create('summary', h3))); + // 2nd level: regexp text + for (const {el, text, urls} of data) { + if (urls) { + // type is partial or full + block.appendChild( + $create('article', [ + $create('h4', {_source: el}, text), + ...urls, + ])); + } else { + // type is none or invalid + block.appendChild($create('a', {tabIndex: 0, _source: el}, text)); } - popup._contents.firstChild.replaceWith(report); - report.onclick = onClick; - if (!report.contains(note)) report.append(note); - }, - }; - - function onClick(event) { - let el = event.target; - if (el._source) { - el._source.focus(); - } else if ((el = el.closest('a'))) { - event.preventDefault(); - API.openURL({ - url: el.href || el.textContent, - currentWindow: null, - }); } } + if (!note) { + note = $create('div.regexp-report-note', + `${t('styleRegexpTestNoteStar')} ${t('styleRegexpTestNote')}` + .split(/(<[^>]+>|\\+)/) + .map((s, i) => i % 2 ? $create('code', s[0] === '<' ? s.slice(1, -1) : s) : s)); + } + popup._contents.firstChild.replaceWith(report); + report.onclick = onClick; + if (!report.contains(note)) report.append(note); +} - function onTabRemoved() { - regexpTester.update(); +function onClick(event) { + let el = event.target; + if (el._source) { + el._source.focus(); + } else if ((el = el.closest('a'))) { + event.preventDefault(); + API.openURL({ + url: el.href || el.textContent, + currentWindow: null, + }); } +} - function onTabUpdated(tabId, info) { - if (info.url) { - regexpTester.update(); - } +function onTabRemoved() { + update(); +} + +function onTabUpdated(tabId, info) { + if (info.url) { + update(); } +} - function unwatch() { - if (isWatching) { - chrome.tabs.onRemoved.removeListener(onTabRemoved); - chrome.tabs.onUpdated.removeListener(onTabUpdated); - for (const el of inputs) observe(el, false); - isWatching = false; - } +function unwatch() { + if (isWatching) { + chrome.tabs.onRemoved.removeListener(onTabRemoved); + chrome.tabs.onUpdated.removeListener(onTabUpdated); + for (const el of inputs) observe(el, false); + isWatching = false; } -})(); +} diff --git a/src/edit/sections-editor-section.js b/src/edit/sections-editor-section.js index c4992b0685d..61ea586c241 100644 --- a/src/edit/sections-editor-section.js +++ b/src/edit/sections-editor-section.js @@ -1,20 +1,18 @@ -/* global $ setupLivePrefs toggleDataset */// dom.js -/* global MozDocMapper helpPopup trimCommentLabel */// util.js -/* global CodeMirror */ -/* global cmFactory */ -/* global debounce */// toolbox.js -/* global editor */ -/* global initBeautifyButton */// beautify.js -/* global linterMan */ -/* global prefs */ -/* global t */// localization.js -'use strict'; +import {$, setupLivePrefs, toggleDataset} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import {MozDocMapper} from '/js/sections-util'; +import {debounce} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import {initBeautifyButton} from './beautify'; +import cmFactory from './codemirror-factory'; +import editor from './editor'; +import linterMan from './linter-manager'; +import {helpPopup, trimCommentLabel} from './util'; const RX_META1 = /^!?\s*==userstyle==\s*$/i; -/* exported EditorSection */ - -class EditorSection { +export default class EditorSection { /** * @param {StyleSection} sectionData * @param {function():number} genId diff --git a/src/edit/sections-editor.js b/src/edit/sections-editor.js index ecceafa4b91..f3546031d6f 100644 --- a/src/edit/sections-editor.js +++ b/src/edit/sections-editor.js @@ -1,18 +1,18 @@ -/* global $ $create $remove messageBoxProxy */// dom.js -/* global API */// msg.js -/* global CodeMirror */ -/* global RX_META UCD */// toolbox.js -/* global MozDocMapper clipString helpPopup rerouteHotkeys showCodeMirrorPopup */// util.js -/* global EditorSection */// sections-editor-section.js -/* global editor */ -/* global linterMan */ -/* global prefs */ -/* global styleSectionsEqual */ // sections-util.js -/* global t */// localization.js -'use strict'; - -/* exported SectionsEditor */ -function SectionsEditor() { +import messageBox from '/js/dlg/message-box'; +import {$, $create, $remove} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {MozDocMapper, styleSectionsEqual} from '/js/sections-util'; +import {clipString, RX_META, UCD} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import {extraKeys} from './codemirror-default'; +import editor from './editor'; +import linterMan from './linter-manager'; +import EditorSection from './sections-editor-section'; +import {helpPopup, rerouteHotkeys, showCodeMirrorPopup} from './util'; + +export default function SectionsEditor() { const {style, /** @type DirtyReporter */dirty} = editor; const container = $('#sections'); /** @type {EditorSection[]} */ @@ -31,7 +31,7 @@ function SectionsEditor() { $('#to-mozilla-help').on('click', showToMozillaHelp); $('#from-mozilla').on('click', () => showMozillaFormatImport()); document.on('wheel', scrollEntirePageOnCtrlShift, {passive: false}); - CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow'; + extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow'; prefs.subscribe('editor.arrowKeysTraverse', (_, val) => { for (const {cm} of sections) handleKeydownSetup(cm, val); upDownJumps = val; @@ -101,7 +101,7 @@ function SectionsEditor() { async replaceStyle(newStyle, draft) { const sameCode = editor.isSame(newStyle); - if (!sameCode && !draft && !await messageBoxProxy.confirm(t('styleUpdateDiscardChanges'))) { + if (!sameCode && !draft && !await messageBox.confirm(t('styleUpdateDiscardChanges'))) { return; } if (!draft) { @@ -126,7 +126,7 @@ function SectionsEditor() { dirty.clear(); // cleaning only after saving has succeeded editor.useSavedStyle(res); } catch (err) { - messageBoxProxy.alert(err.message || err); + messageBox.alert(err.message || err); } }, @@ -413,7 +413,7 @@ function SectionsEditor() { const code = popup.codebox.getValue().trim(); if (!RX_META.test(code) || !await getPreprocessor(code) || - await messageBoxProxy.confirm( + await messageBox.confirm( t('importPreprocessor'), 'pre-line', t('importPreprocessorTitle')) ) { @@ -450,7 +450,7 @@ function SectionsEditor() { } function showError(errors) { - messageBoxProxy.show({ + messageBox.show({ className: 'center danger', title: t('styleFromMozillaFormatError'), contents: $create('pre', diff --git a/src/edit/settings.js b/src/edit/settings.js index b7e31a1a5e7..7584c1ab71d 100644 --- a/src/edit/settings.js +++ b/src/edit/settings.js @@ -1,14 +1,14 @@ -/* global $ $create setupLivePrefs */// dom.js -/* global API */// msg.js -/* global CodeMirror */ -/* global CODEMIRROR_THEMES */ -/* global editor */ -/* global helpPopup createHotkeyInput */// util.js -/* global linterMan */ -/* global prefs */ -/* global t */// localization.js -/* global debounce tryURL */// toolbox.js -'use strict'; +import {$, $create, setupLivePrefs} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {debounce, tryURL} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import CODEMIRROR_THEMES from './codemirror-themes'; +import editor from './editor'; +import {showLintConfig} from './linter-dialogs'; +import showKeymapHelp from './show-keymap-help'; +import {createHotkeyInput, helpPopup} from './util'; // TODO: allow the user to customize which options are always shown // TODO: decide which options are shown by default @@ -172,7 +172,7 @@ function EditorSettings(ui) { //#region Theme $('#editor\\.theme', ui).append(...[ $create('option', {value: 'default'}, t('defaultTheme')), - ...Object.keys(CODEMIRROR_THEMES).map(s => $create('option', s)), + ...CODEMIRROR_THEMES.map(s => $create('option', s)), ]); //#endregion @@ -185,12 +185,8 @@ function EditorSettings(ui) { popup.style = `top: ${bounds.bottom}px; left: ${bounds.left}px; right: auto;`; $('input', popup).focus(); }; - $('#keyMap-help', ui).onclick = () => { - require(['/edit/show-keymap-help'], () => showKeymapHelp()); /* global showKeymapHelp */ - }; - $('#linter-settings', ui).onclick = () => { - require(['/edit/linter-dialogs'], () => linterMan.showLintConfig()); - }; + $('#keyMap-help', ui).onclick = showKeymapHelp; + $('#linter-settings', ui).onclick = showLintConfig; //#endregion setupLivePrefs(ui); diff --git a/src/edit/show-keymap-help.js b/src/edit/show-keymap-help.js index da11d3db6c9..5d173399e39 100644 --- a/src/edit/show-keymap-help.js +++ b/src/edit/show-keymap-help.js @@ -1,15 +1,14 @@ -/* global $$ $create */// dom.js -/* global CodeMirror */ -/* global helpPopup */// util.js -/* global prefs */ -/* global clipString stringAsRegExp */// toolbox.js -/* global t */// localization.js -'use strict'; +import {$$, $create} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import {clipString, stringAsRegExp} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import {extraKeys} from './codemirror-default'; +import {helpPopup} from './util'; -/* exported showKeymapHelp */ -function showKeymapHelp() { +export default function showKeymapHelp() { const PREF = 'editor.keyMap'; - const keyMap = mergeKeyMaps({}, prefs.get(PREF), CodeMirror.defaults.extraKeys); + const keyMap = mergeKeyMaps({}, prefs.get(PREF), extraKeys); const keyMapSorted = Object.keys(keyMap) .map(key => ({key, cmd: keyMap[key]})) .sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1)); diff --git a/src/edit/source-editor.js b/src/edit/source-editor.js index f03c97164a9..3e669f0b16c 100644 --- a/src/edit/source-editor.js +++ b/src/edit/source-editor.js @@ -1,20 +1,19 @@ -/* global $ $$remove $create $createLink $isTextInput messageBoxProxy */// dom.js -/* global API */// msg.js -/* global CodeMirror */ -/* global MozDocMapper failRegexp */// util.js -/* global MozSectionFinder */ -/* global MozSectionWidget */ -/* global UCD RX_META */// toolbox.js -/* global chromeSync */// storage-util.js -/* global cmFactory */ -/* global editor */ -/* global linterMan */ -/* global prefs */ -/* global t */// localization.js -'use strict'; +import messageBox from '/js/dlg/message-box'; +import {$, $$remove, $create, $createLink, $isTextInput} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {MozDocMapper} from '/js/sections-util'; +import {chromeSync} from '/js/storage-util'; +import {RX_META, UCD} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import cmFactory from './codemirror-factory'; +import editor, {failRegexp} from './editor'; +import linterMan from './linter-manager'; +import MozSectionFinder from './moz-section-finder'; +import MozSectionWidget from './moz-section-widget'; -/* exported SourceEditor */ -async function SourceEditor() { +export default async function SourceEditor() { const {style, /** @type DirtyReporter */dirty} = editor; const DEFAULT_TEMPLATE = ` /* ==UserStyle== @@ -92,13 +91,13 @@ async function SourceEditor() { const {customName, enabled, id} = style; res = !id && await API.usercss.build({sourceCode, checkDup: true, metaOnly: true}); if (res && res.dup) { - messageBoxProxy.alert(t('usercssAvoidOverwriting'), 'danger', t('genericError')); + messageBox.alert(t('usercssAvoidOverwriting'), 'danger', t('genericError')); } else { res = await API.usercss.editSave({customName, enabled, id, sourceCode}); // Awaiting inside `try` so that exceptions go to our `catch` await replaceStyle(res.style); if ((res.badRe = getBadRegexps(res.style))) { - messageBoxProxy.alert(res.badRe, 'danger pre', t('styleBadRegexp')); + messageBox.alert(res.badRe, 'danger pre', t('styleBadRegexp')); } } showLog(res.log); @@ -215,7 +214,7 @@ async function SourceEditor() { return; } - if (draft || await messageBoxProxy.confirm(t('styleUpdateDiscardChanges'))) { + if (draft || await messageBox.confirm(t('styleUpdateDiscardChanges'))) { editor.useSavedStyle(newStyle); if (!sameCode) { const si0 = draft && draft.si.cms[0]; @@ -239,7 +238,7 @@ async function SourceEditor() { } async function saveTemplate() { - const res = await messageBoxProxy.show({ + const res = await messageBox.show({ contents: t('usercssReplaceTemplateConfirmation'), className: 'center', buttons: [t('confirmYes'), t('confirmNo'), { @@ -252,7 +251,7 @@ async function SourceEditor() { const code = res.button === 2 ? DEFAULT_TEMPLATE : cm.getValue(); await chromeSync.setLZValue(key, code); if (await chromeSync.getLZValue(key) !== code) { - messageBoxProxy.alert(t('syncStorageErrorSaving')); + messageBox.alert(t('syncStorageErrorSaving')); } } } @@ -268,7 +267,7 @@ async function SourceEditor() { const pp = errStyle[UCD].preprocessor; const ppUrl = editor.ppDemo[pp]; cm.setSelections(points.map(p => ({anchor: p, head: p}))); - messageBoxProxy.show({ + messageBox.show({ title: t('genericError'), className: 'center pre danger', contents: $create('pre', diff --git a/src/edit/usw-integration.js b/src/edit/usw-integration.js index d1a6604cd91..5c0be8df202 100644 --- a/src/edit/usw-integration.js +++ b/src/edit/usw-integration.js @@ -1,11 +1,13 @@ -/* global $$ $ $create $remove messageBoxProxy showSpinner toggleDataset */// dom.js -/* global API msg */// msg.js -/* global URLS isEmptyObj */// toolbox.js -/* global editor */ -/* global t */// localization.js -'use strict'; +import messageBox from '/js/dlg/message-box'; +import {$, $$, $create, $remove, showSpinner, toggleDataset} from '/js/dom'; +import {t} from '/js/localization'; +import * as msg from '/js/msg'; +import {API} from '/js/msg'; +import {isEmptyObj, URLS} from '/js/toolbox'; +import editor from './editor'; +import styleReady from './style-ready'; -editor.styleReady.then(() => { +styleReady.then(() => { const ERROR_TITLE = 'UserStyles.world ' + t('genericError'); const elProgress = $('#usw-progress'); const UI = $('#publish'); @@ -30,7 +32,7 @@ editor.styleReady.then(() => { async function publishStyle() { const {id, _usw} = style; if (await API.data.has('usw' + id) && - !await messageBoxProxy.confirm(t('publishRetry'), 'danger', ERROR_TITLE)) { + !await messageBox.confirm(t('publishRetry'), 'danger', ERROR_TITLE)) { return; } let error; diff --git a/src/edit/util.js b/src/edit/util.js index a9e5e6c0515..1fa9e7f487e 100644 --- a/src/edit/util.js +++ b/src/edit/util.js @@ -1,12 +1,13 @@ -/* global $$ $ $create getEventKeyName messageBoxProxy moveFocus */// dom.js -/* global CodeMirror */ -/* global editor */ -/* global prefs */ -/* global clipString */// toolbox.js -/* global t */// localization.js -'use strict'; - -const helpPopup = { +import messageBox from '/js/dlg/message-box'; +import {$, $$, $create, getEventKeyName, moveFocus} from '/js/dom'; +import {t} from '/js/localization'; +import * as prefs from '/js/prefs'; +import {clipString} from '/js/toolbox'; +import CodeMirror from 'codemirror'; +import {extraKeys} from './codemirror-default'; +import editor from './editor'; + +export const helpPopup = { SEL: '#help-popup', /** @@ -48,7 +49,7 @@ const helpPopup = { } if (event && (el = div.codebox) && !el.options.readOnly && !el.isClean()) { setTimeout(async () => { - const ok = await messageBoxProxy.confirm(t('confirmDiscardChanges')); + const ok = await messageBox.confirm(t('confirmDiscardChanges')); return ok && helpPopup.close(); }); return; @@ -64,7 +65,7 @@ const helpPopup = { }; // reroute handling to nearest editor when keypress resolves to one of these commands -const rerouteHotkeys = { +export const rerouteHotkeys = { commands: [ 'beautify', 'colorpicker', @@ -97,15 +98,14 @@ const rerouteHotkeys = { } }; if (CodeMirror.lookupKey(keyName, CodeMirror.defaults.keyMap, rerouteCommand) === 'handled' || - CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, rerouteCommand) === 'handled') { + CodeMirror.lookupKey(keyName, extraKeys, rerouteCommand) === 'handled') { event.preventDefault(); event.stopPropagation(); } }, }; -/* exported createHotkeyInput */ -function createHotkeyInput(prefId, {buttons = true, onDone}) { +export function createHotkeyInput(prefId, {buttons = true, onDone}) { const RX_ERR = new RegExp('^(' + [ /Space/, /(Shift-)?./, // a single character @@ -170,8 +170,7 @@ function createHotkeyInput(prefId, {buttons = true, onDone}) { } } -/* exported showCodeMirrorPopup */ -function showCodeMirrorPopup(title, html, options) { +export function showCodeMirrorPopup(title, html, options) { const popup = helpPopup.show(title, html, {className: 'big'}); let cm = popup.codebox = CodeMirror(popup._contents, Object.assign({ @@ -209,28 +208,7 @@ function showCodeMirrorPopup(title, html, options) { return popup; } -/* exported trimCommentLabel */ -function trimCommentLabel(str, limit = 1000) { +export function trimCommentLabel(str, limit = 1000) { // stripping /*** foo ***/ to foo return clipString(str.replace(/^[!-/:;=\s]*|[-#$&(+,./:;<=>\s*]*$/g, ''), limit); } - -function failRegexp(r) { - try { - new RegExp(r); - r = ''; - } catch (err) { - r = err.message.split('/:').pop().trim(); - } - return r; -} - -/* exported validateRegexp */ -function validateRegexp({target: el}) { - let err = failRegexp(el.value); - if (err) err = t('styleBadRegexp') + '\n' + err; - if (el.title !== err) { - el.title = err; - el.setCustomValidity(err); - } -} diff --git a/src/edit/windowed-mode.js b/src/edit/windowed-mode.js index 87502f08403..163df69a179 100644 --- a/src/edit/windowed-mode.js +++ b/src/edit/windowed-mode.js @@ -1,6 +1,8 @@ +import browser from '/js/browser'; import * as prefs from '/js/prefs'; -import {FIREFOX, getOwnTab, sessionStore, tryJSONparse} from '/js/toolbox'; +import {getOwnTab, sessionStore, tryJSONparse} from '/js/toolbox'; import editor from './editor'; +import EmbeddedPopup from './embedded-popup'; let ownTabId; if (chrome.windows) { @@ -24,7 +26,7 @@ async function initWindowedMode() { chrome.tabs.onAttached.addListener(onTabAttached); // Chrome 96+ bug: the type is 'app' for a window that was restored via Ctrl-Shift-T const isSimple = ['app', 'popup'].includes((await browser.windows.getCurrent()).type); - if (isSimple) require(['/edit/embedded-popup']); + if (isSimple) EmbeddedPopup(); editor.isWindowed = isSimple || ( history.length === 1 && await prefs.ready && prefs.get('openEditInWindow') && diff --git a/src/injection-order/injection-order.js b/src/injection-order/injection-order.js index af37c589a8a..80e020e7f39 100644 --- a/src/injection-order/injection-order.js +++ b/src/injection-order/injection-order.js @@ -1,13 +1,11 @@ -/* global $create messageBoxProxy */// dom.js -/* global API */// msg.js -/* global DraggableList */ -/* global t */// localization.js -'use strict'; +import messageBox from '/js/dlg/message-box'; +import {$create} from '/js/dom'; +import {API} from '/js/msg'; +import {t} from '/js/localization'; -/* exported InjectionOrder */ -async function InjectionOrder(show, el, selector) { +export async function InjectionOrder(show, el, selector) { if (!show) { - return messageBoxProxy.close(); + return messageBox.close(); } const SEL_ENTRY = '.injection-order-entry'; const groups = await API.styles.getAllOrdered(['_id', 'id', 'name', 'enabled']); @@ -24,7 +22,7 @@ async function InjectionOrder(show, el, selector) { title: t('styleInjectionImportance'), }), ]); - await messageBoxProxy.show({ + await messageBox.show({ title: t('styleInjectionOrder'), contents: $create('fragment', Object.entries(groups).map(makeList)), className: 'center-dialog ' + selector.slice(1), @@ -74,6 +72,7 @@ async function InjectionOrder(show, el, selector) { API.styles.setOrder(groups); } }); + /* global DraggableList */ DraggableList(ol, {scrollContainer: ol}); return $create('section', {['data-' + type]: ''}, [ $create('header', t(`styleInjectionOrderHint${type === 'main' ? '' : '_' + type}`)), diff --git a/src/install-usercss/install-usercss.js b/src/install-usercss/install-usercss.js index 5b1660800d1..ee088795d56 100644 --- a/src/install-usercss/install-usercss.js +++ b/src/install-usercss/install-usercss.js @@ -1,15 +1,13 @@ -/* global $$ $ $create $createLink $$remove showSpinner */// dom.js -/* global API */// msg.js -/* global CODEMIRROR_THEMES */ -/* global CodeMirror */ -/* global UCD URLS clipString closeCurrentTab deepEqual sessionStore tryURL */// toolbox.js -/* global compareVersion */// cmpver.js -/* global messageBox */ -/* global prefs */ -/* global preinit */ -/* global styleCodeEmpty */// sections-util.js -/* global t */// localization.js -'use strict'; +import CODEMIRROR_THEMES from '/edit/codemirror-themes'; +import compareVersion from '/js/cmpver'; +import messageBox from '/js/dlg/message-box'; +import {$, $$, $$remove, $create, $createLink, showSpinner} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {styleCodeEmpty} from '/js/sections-util'; +import {clipString, closeCurrentTab, deepEqual, sessionStore, tryURL, UCD, URLS} from '/js/toolbox'; +import CodeMirror from 'codemirror'; const CFG_SEL = '#message-box.config-dialog'; let cfgShown = true; @@ -248,8 +246,7 @@ function updateMeta(style, dup = installedDup) { } async function openConfigDialog() { - await require(['/js/dlg/config-dialog']); /* global configDialog */ - configDialog(style); + (await import('/js/dlg/config-dialog')).default(style); } } @@ -307,7 +304,7 @@ function enablePostActions() { $('#edit').search = `?id=${id}`; $('#delete').onclick = async () => { if (await messageBox.confirm(t('deleteStyleConfirm'), 'danger center', t('confirmDelete'))) { - await API.styles.delete(id); + await API.styles.remove(id); if (tabId < 0 && history.length > 1) { history.back(); } else { diff --git a/src/install-usercss/preinit.js b/src/install-usercss/preinit.js index f83ee3857bc..ed9fb55cac7 100644 --- a/src/install-usercss/preinit.js +++ b/src/install-usercss/preinit.js @@ -1,7 +1,7 @@ -/* global API */// msg.js -/* global CHROME closeCurrentTab */// toolbox.js -/* global t */// localization.js -'use strict'; +import browser from '/js/browser'; +import {API} from '/js/msg'; +import {CHROME, closeCurrentTab} from '/js/toolbox'; +import {t} from '/js/localization'; /* exported preinit */ const preinit = (() => { diff --git a/src/js/browser.js b/src/js/browser.js index 8741ba2f297..eec62b9e3e6 100644 --- a/src/js/browser.js +++ b/src/js/browser.js @@ -1,6 +1,7 @@ -'use strict'; - -if (!(self.browser || {}).runtime) { +let browser; +if (__BUILD === 'CHROME_MV3') { + browser = self.browser = chrome; +} else if (__BUILD === 'CHROME' || !self.browser?.runtime) { /* Auto-promisifier with a fallback to direct call on signature error. The fallback isn't used now since we call all synchronous methods via `chrome` */ const directEvents = ['addListener', 'removeListener', 'hasListener', 'hasListeners']; @@ -59,6 +60,7 @@ if (!(self.browser || {}).runtime) { return target[key] || proxify(src, srcName, target, key); }, }); - // Not assigning directly to let IDE use @types/firefox-webext-browser - Object.assign(self, {browser: createProxy(chrome)}); + browser = self.browser = createProxy(chrome); } + +export default browser; diff --git a/src/js/cmpver.js b/src/js/cmpver.js index 5ff46ba2e5e..b5bbd3995e0 100644 --- a/src/js/cmpver.js +++ b/src/js/cmpver.js @@ -1,17 +1,13 @@ -'use strict'; - /** Copied from https://github.com/violentmonkey/violentmonkey/blob/master/src/common/util.js and switched to Math.sign */ -/* exported compareVersion */ - const VERSION_RE = /^(.*?)-([-.0-9a-z]+)|$/i; const DIGITS_RE = /^\d+$/; // using regexp to avoid +'1e2' being parsed as 100 /** @return -1 | 0 | 1 */ -function compareVersion(ver1, ver2) { +export default function compareVersion(ver1, ver2) { const [, main1 = ver1 || '', pre1] = VERSION_RE.exec(ver1); const [, main2 = ver2 || '', pre2] = VERSION_RE.exec(ver2); const delta = compareVersionChunk(main1, main2) diff --git a/src/js/color/color-converter.js b/src/js/color/color-converter.js index 269b8543227..ed8a7b9d7a1 100644 --- a/src/js/color/color-converter.js +++ b/src/js/color/color-converter.js @@ -1,277 +1,262 @@ -'use strict'; +let HEX; -const colorConverter = (NAMED_COLORS => { +export const ALPHA_DIGITS = 3; +// All groups in RXS_NUM must use ?: in order to enable \1 in RX_COLOR.rgb +const RXS_NUM = /\s*[+-]?(\.\d+|\d+(\.\d*)?)(e[+-]?\d+)?/.source.replace(/\(/g, '(?:'); +const RXS_ANGLE = '(?:deg|g?rad|turn)?'; +const expandRe = re => RegExp(re.source.replace(/N/g, RXS_NUM).replace(/A/g, RXS_ANGLE), 'iy'); +export const RX_COLOR = { + hex: /#([a-f\d]{3}(?:[a-f\d](?:[a-f\d]{2}){0,2})?)\b/iy, + // num_or_angle, pct, pct [ , num_or_pct]? + // num_or_angle pct pct [ / num_or_pct]? + hsl: expandRe(/^NA(\s*(,N%\s*){2}(,N%?\s*)?|(\s+N%){2}\s*(\/N%?\s*)?)$/), + // num_or_angle|none pct|none pct|none [ / num_or_pct|none ]? + hwb: expandRe(/^(NA|none)(\s+(N%|none)){2}\s*(\/(N%?|none)\s*)?$/), + // num, num, num [ , num_or_pct]? + // pct, pct, pct [ , num_or_pct]? + // num num num [ / num_or_pct]? + // pct pct pct [ / num_or_pct]? + rgb: expandRe(/^N(%?)(\s*,N\1\s*,N\1\s*(,N%?\s*)?|\s+N\1\s+N\1\s*(\/N%?\s*)?)$/), +}; +const ANGLE_TO_DEG = { + grad: 360 / 400, + rad: 180 / Math.PI, + turn: 360, +}; +const TO_HSV = { + hex: RGBtoHSV, + hsl: HSLtoHSV, + hwb: HWBtoHSV, + rgb: RGBtoHSV, +}; +const FROM_HSV = { + hex: HSVtoRGB, + hsl: HSVtoHSL, + hwb: HSVtoHWB, + rgb: HSVtoRGB, +}; +export const guessType = c => + 'r' in c ? 'rgb' : + 'w' in c ? 'hwb' : + 'v' in c ? 'hsv' : + 'l' in c ? 'hsl' : + undefined; +export const fromHSV = (color, type) => FROM_HSV[type](color); +export const toHSV = color => TO_HSV[color.type || 'rgb'](color); - // All groups in RXS_NUM must use ?: in order to enable \1 in RX_COLOR.rgb - const RXS_NUM = /\s*[+-]?(\.\d+|\d+(\.\d*)?)(e[+-]?\d+)?/.source.replace(/\(/g, '(?:'); - const RXS_ANGLE = '(?:deg|g?rad|turn)?'; - const expandRe = re => RegExp(re.source.replace(/N/g, RXS_NUM).replace(/A/g, RXS_ANGLE), 'iy'); - const RX_COLOR = { - hex: /#([a-f\d]{3}(?:[a-f\d](?:[a-f\d]{2}){0,2})?)\b/iy, - // num_or_angle, pct, pct [ , num_or_pct]? - // num_or_angle pct pct [ / num_or_pct]? - hsl: expandRe(/^NA(\s*(,N%\s*){2}(,N%?\s*)?|(\s+N%){2}\s*(\/N%?\s*)?)$/), - // num_or_angle|none pct|none pct|none [ / num_or_pct|none ]? - hwb: expandRe(/^(NA|none)(\s+(N%|none)){2}\s*(\/(N%?|none)\s*)?$/), - // num, num, num [ , num_or_pct]? - // pct, pct, pct [ , num_or_pct]? - // num num num [ / num_or_pct]? - // pct pct pct [ / num_or_pct]? - rgb: expandRe(/^N(%?)(\s*,N\1\s*,N\1\s*(,N%?\s*)?|\s+N\1\s+N\1\s*(\/N%?\s*)?)$/), - }; - const ANGLE_TO_DEG = { - grad: 360 / 400, - rad: 180 / Math.PI, - turn: 360, - }; - const TO_HSV = { - hex: RGBtoHSV, - hsl: HSLtoHSV, - hwb: HWBtoHSV, - rgb: RGBtoHSV, - }; - const FROM_HSV = { - hex: HSVtoRGB, - hsl: HSVtoHSL, - hwb: HSVtoHWB, - rgb: HSVtoRGB, - }; - const guessType = c => - 'r' in c ? 'rgb' : - 'w' in c ? 'hwb' : - 'v' in c ? 'hsv' : - 'l' in c ? 'hsl' : - undefined; - let HEX; - - return { - parse, - format, - formatAlpha, - fromHSV: (color, type) => FROM_HSV[type](color), - toHSV: color => TO_HSV[color.type || 'rgb'](color), - constrain, - constrainHue, - guessType, - snapToInt, - testAt, - ALPHA_DIGITS: 3, - NAMED_COLORS, - RX_COLOR, - }; - - function format(color = '', type = color.type, {hexUppercase, usoMode, round} = {}) { - if (!color || !type) return typeof color === 'string' ? color : ''; - const {a, type: src = guessType(color)} = color; - const aFmt = formatAlpha(a); - const aStr = aFmt ? ', ' + aFmt : ''; - const srcConv = src === 'hex' ? 'rgb' : src; - const dstConv = type === 'hex' ? 'rgb' : type; - color = srcConv === dstConv ? color : FROM_HSV[dstConv](TO_HSV[srcConv](color)); - round = round ? Math.round : v => v; - const {r, g, b, h, s, l, w} = color; - switch (type) { - case 'hex': { - let res = '#' + hex2(r) + hex2(g) + hex2(b) + (aStr ? hex2(Math.round(a * 255)) : ''); - if (!usoMode) res = res.replace(/^#(.)\1(.)\2(.)\3(?:(.)\4)?$/, '#$1$2$3$4'); - return hexUppercase ? res.toUpperCase() : res; - } - case 'rgb': { - const rgb = [r, g, b].map(Math.round).join(', '); - return usoMode ? rgb : `rgb${aStr ? 'a' : ''}(${rgb}${aStr})`; - } - case 'hsl': - return `hsl${aStr ? 'a' : ''}(${round(h)}, ${round(s)}%, ${round(l)}%${aStr})`; - case 'hwb': - return `hwb(${round(h)} ${round(w)}% ${round(b)}%${aFmt ? ' / ' + aFmt : ''})`; +export function format(color = '', type = color.type, {hexUppercase, usoMode, round} = {}) { + if (!color || !type) return typeof color === 'string' ? color : ''; + const {a, type: src = guessType(color)} = color; + const aFmt = formatAlpha(a); + const aStr = aFmt ? ', ' + aFmt : ''; + const srcConv = src === 'hex' ? 'rgb' : src; + const dstConv = type === 'hex' ? 'rgb' : type; + color = srcConv === dstConv ? color : FROM_HSV[dstConv](TO_HSV[srcConv](color)); + round = round ? Math.round : v => v; + const {r, g, b, h, s, l, w} = color; + switch (type) { + case 'hex': { + let res = '#' + hex2(r) + hex2(g) + hex2(b) + (aStr ? hex2(Math.round(a * 255)) : ''); + if (!usoMode) res = res.replace(/^#(.)\1(.)\2(.)\3(?:(.)\4)?$/, '#$1$2$3$4'); + return hexUppercase ? res.toUpperCase() : res; } - } - - function parse(s) { - if (typeof s !== 'string' || !(s = s.trim())) { - return; - } else if (s[0] === '#') { - return parseHex(s); - } else if (s.endsWith(')') && (s = s.match(/^(hwb|(hsl|rgb)a?)\(\s*([^)]+)/i))) { - return parseFunc((s[2] || s[1]).toLowerCase(), s[3]); - } else { - return colorConverter.NAMED_COLORS.get(s.toLowerCase()); + case 'rgb': { + const rgb = [r, g, b].map(Math.round).join(', '); + return usoMode ? rgb : `rgb${aStr ? 'a' : ''}(${rgb}${aStr})`; } + case 'hsl': + return `hsl${aStr ? 'a' : ''}(${round(h)}, ${round(s)}%, ${round(l)}%${aStr})`; + case 'hwb': + return `hwb(${round(h)} ${round(w)}% ${round(b)}%${aFmt ? ' / ' + aFmt : ''})`; } +} - function initHexMap() { - HEX = Array(256).fill(-0xFFFF); // ensuring a PACKED_SMI array - for (let i = 48; i < 58; i++) HEX[i] = i - 48; // 0123456789 - for (let i = 65; i < 71; i++) HEX[i] = i - 65 + 10; // ABCDEF - for (let i = 97; i < 103; i++) HEX[i] = i - 97 + 10; // abcdef +export function parse(s) { + if (typeof s !== 'string' || !(s = s.trim())) { + return; + } else if (s[0] === '#') { + return parseHex(s); + } else if (s.endsWith(')') && (s = s.match(/^(hwb|(hsl|rgb)a?)\(\s*([^)]+)/i))) { + return parseFunc((s[2] || s[1]).toLowerCase(), s[3]); + } else { + return NAMED_COLORS.get(s.toLowerCase()); // eslint-disable-line no-use-before-define } +} - function parseHex(str) { - if (!HEX) initHexMap(); - let r, g, b, a; - const len = str.length; - if (len === 4 || len === 5 - ? (r = HEX[str.charCodeAt(1)] * 0x11) >= 0 && - (g = HEX[str.charCodeAt(2)] * 0x11) >= 0 && - (b = HEX[str.charCodeAt(3)] * 0x11) >= 0 && - (len < 5 || (a = HEX[str.charCodeAt(4)] * 0x11 / 255) >= 0) - : (len === 7 || len === 9) && - (r = HEX[str.charCodeAt(1)] * 0x10 + HEX[str.charCodeAt(2)]) >= 0 && - (g = HEX[str.charCodeAt(3)] * 0x10 + HEX[str.charCodeAt(4)]) >= 0 && - (b = HEX[str.charCodeAt(5)] * 0x10 + HEX[str.charCodeAt(6)]) >= 0 && - (len < 9 || (a = (HEX[str.charCodeAt(7)] * 0x10 + HEX[str.charCodeAt(8)]) / 255) >= 0) - ) { - return {type: 'hex', r, g, b, a}; - } - } +function initHexMap() { + HEX = Array(256).fill(-0xFFFF); // ensuring a PACKED_SMI array + for (let i = 48; i < 58; i++) HEX[i] = i - 48; // 0123456789 + for (let i = 65; i < 71; i++) HEX[i] = i - 65 + 10; // ABCDEF + for (let i = 97; i < 103; i++) HEX[i] = i - 97 + 10; // abcdef +} - function parseFunc(type, val) { - if (!testAt(RX_COLOR[type], 0, val)) { - return; - } - // Not using destructuring because it's slow - const parts = val.trim().split(/\s*[,/]\s*|\s+/); - const n1 = parseFloat(parts[0]); - const n2 = parseFloat(parts[1]); - const n3 = parseFloat(parts[2]); - const nA = parseFloat(parts[3]); - const a = isNaN(nA) ? undefined : constrain(0, 1, parts[3].endsWith('%') ? nA / 100 : nA); - if (type === 'rgb') { - const k = parts[0].endsWith('%') ? 2.55 : 1; - return { - type, - r: constrain(0, 255, Math.round(n1 * k)), - g: constrain(0, 255, Math.round(n2 * k)), - b: constrain(0, 255, Math.round(n3 * k)), - a, - }; - } - const h = constrainHue(n1 * (ANGLE_TO_DEG[parts[0].match(/\D*$/)[0].toLowerCase()] || 1)); - const n2c = constrain(0, 100, n2 || 0); - const n3c = constrain(0, 100, n3 || 0); - return type === 'hwb' - ? {type, h, w: n2c, b: n3c, a} - : {type, h, s: n2c, l: n3c, a}; +function parseHex(str) { + if (!HEX) initHexMap(); + let r, g, b, a; + const len = str.length; + if (len === 4 || len === 5 + ? (r = HEX[str.charCodeAt(1)] * 0x11) >= 0 && + (g = HEX[str.charCodeAt(2)] * 0x11) >= 0 && + (b = HEX[str.charCodeAt(3)] * 0x11) >= 0 && + (len < 5 || (a = HEX[str.charCodeAt(4)] * 0x11 / 255) >= 0) + : (len === 7 || len === 9) && + (r = HEX[str.charCodeAt(1)] * 0x10 + HEX[str.charCodeAt(2)]) >= 0 && + (g = HEX[str.charCodeAt(3)] * 0x10 + HEX[str.charCodeAt(4)]) >= 0 && + (b = HEX[str.charCodeAt(5)] * 0x10 + HEX[str.charCodeAt(6)]) >= 0 && + (len < 9 || (a = (HEX[str.charCodeAt(7)] * 0x10 + HEX[str.charCodeAt(8)]) / 255) >= 0) + ) { + return {type: 'hex', r, g, b, a}; } +} - function formatAlpha(a) { - return isNaN(a) ? '' : - (a + .5 * Math.pow(10, -colorConverter.ALPHA_DIGITS)) - .toFixed(colorConverter.ALPHA_DIGITS + 1) - .slice(0, -1) - .replace(/^0(?=\.[1-9])|^1\.0+?$|\.?0+$/g, ''); +function parseFunc(type, val) { + if (!testAt(RX_COLOR[type], 0, val)) { + return; } - - function RGBtoHSV({r, g, b, a}) { - r /= 255; - g /= 255; - b /= 255; - const MaxC = Math.max(r, g, b); - const MinC = Math.min(r, g, b); - const DeltaC = MaxC - MinC; - - let h = - DeltaC === 0 ? 0 : - MaxC === r ? 60 * (((g - b) / DeltaC) % 6) : - MaxC === g ? 60 * (((b - r) / DeltaC) + 2) : - MaxC === b ? 60 * (((r - g) / DeltaC) + 4) : - 0; - h = constrainHue(h); + // Not using destructuring because it's slow + const parts = val.trim().split(/\s*[,/]\s*|\s+/); + const n1 = parseFloat(parts[0]); + const n2 = parseFloat(parts[1]); + const n3 = parseFloat(parts[2]); + const nA = parseFloat(parts[3]); + const a = isNaN(nA) ? undefined : constrain(0, 1, parts[3].endsWith('%') ? nA / 100 : nA); + if (type === 'rgb') { + const k = parts[0].endsWith('%') ? 2.55 : 1; return { - h, - s: MaxC === 0 ? 0 : DeltaC / MaxC, - v: MaxC, + type, + r: constrain(0, 255, Math.round(n1 * k)), + g: constrain(0, 255, Math.round(n2 * k)), + b: constrain(0, 255, Math.round(n3 * k)), a, }; } + const h = constrainHue(n1 * (ANGLE_TO_DEG[parts[0].match(/\D*$/)[0].toLowerCase()] || 1)); + const n2c = constrain(0, 100, n2 || 0); + const n3c = constrain(0, 100, n3 || 0); + return type === 'hwb' + ? {type, h, w: n2c, b: n3c, a} + : {type, h, s: n2c, l: n3c, a}; +} - function HSVtoRGB({h, s, v, a}) { - h = constrainHue(h); - const C = s * v; - const X = C * (1 - Math.abs((h / 60) % 2 - 1)); - const m = v - C; - const [r, g, b] = - h >= 0 && h < 60 ? [C, X, 0] : - h >= 60 && h < 120 ? [X, C, 0] : - h >= 120 && h < 180 ? [0, C, X] : - h >= 180 && h < 240 ? [0, X, C] : - h >= 240 && h < 300 ? [X, 0, C] : - h >= 300 && h < 360 ? [C, 0, X] : []; - return { - r: snapToInt(Math.round((r + m) * 255)), - g: snapToInt(Math.round((g + m) * 255)), - b: snapToInt(Math.round((b + m) * 255)), - a, - }; - } +export function formatAlpha(a) { + return isNaN(a) ? '' : + (a + .5 * Math.pow(10, -ALPHA_DIGITS)) + .toFixed(ALPHA_DIGITS + 1) + .slice(0, -1) + .replace(/^0(?=\.[1-9])|^1\.0+?$|\.?0+$/g, ''); +} +function RGBtoHSV({r, g, b, a}) { + r /= 255; + g /= 255; + b /= 255; + const MaxC = Math.max(r, g, b); + const MinC = Math.min(r, g, b); + const DeltaC = MaxC - MinC; - function HSLtoHSV({h, s, l, a}) { - const t = s * (l < 50 ? l : 100 - l) / 100; - return { - h: constrainHue(h), - s: t + l ? 200 * t / (t + l) / 100 : 0, - v: (t + l) / 100, - a, - }; - } + let h = + DeltaC === 0 ? 0 : + MaxC === r ? 60 * (((g - b) / DeltaC) % 6) : + MaxC === g ? 60 * (((b - r) / DeltaC) + 2) : + MaxC === b ? 60 * (((r - g) / DeltaC) + 4) : + 0; + h = constrainHue(h); + return { + h, + s: MaxC === 0 ? 0 : DeltaC / MaxC, + v: MaxC, + a, + }; +} - function HSVtoHSL({h, s, v, a}) { - const l = (2 - s) * v / 2; - const t = l < .5 ? l * 2 : 2 - l * 2; - return { - h: constrainHue(h), - s: t ? s * v / t * 100 : 0, - l: l * 100, - a, - }; - } +function HSVtoRGB({h, s, v, a}) { + h = constrainHue(h); + const C = s * v; + const X = C * (1 - Math.abs((h / 60) % 2 - 1)); + const m = v - C; + const [r, g, b] = + h >= 0 && h < 60 ? [C, X, 0] : + h >= 60 && h < 120 ? [X, C, 0] : + h >= 120 && h < 180 ? [0, C, X] : + h >= 180 && h < 240 ? [0, X, C] : + h >= 240 && h < 300 ? [X, 0, C] : + h >= 300 && h < 360 ? [C, 0, X] : []; + return { + r: snapToInt(Math.round((r + m) * 255)), + g: snapToInt(Math.round((g + m) * 255)), + b: snapToInt(Math.round((b + m) * 255)), + a, + }; +} - function HWBtoHSV({h, w, b, a}) { - w = constrain(0, 100, w) / 100; - b = constrain(0, 100, b) / 100; - return { - h: constrainHue(h), - s: b === 1 ? 0 : 1 - w / (1 - b), - v: 1 - b, - a, - }; - } - function HSVtoHWB({h, s, v, a}) { - return { - h: constrainHue(h), - w: (1 - s) * v * 100, - b: (1 - v) * 100, - a, - }; - } +function HSLtoHSV({h, s, l, a}) { + const t = s * (l < 50 ? l : 100 - l) / 100; + return { + h: constrainHue(h), + s: t + l ? 200 * t / (t + l) / 100 : 0, + v: (t + l) / 100, + a, + }; +} - function constrain(min, max, value) { - return value < min ? min : value > max ? max : value; - } +function HSVtoHSL({h, s, v, a}) { + const l = (2 - s) * v / 2; + const t = l < .5 ? l * 2 : 2 - l * 2; + return { + h: constrainHue(h), + s: t ? s * v / t * 100 : 0, + l: l * 100, + a, + }; +} - function constrainHue(h) { - return h < 0 ? h % 360 + 360 : - h >= 360 ? h % 360 : - h; - } +function HWBtoHSV({h, w, b, a}) { + w = constrain(0, 100, w) / 100; + b = constrain(0, 100, b) / 100; + return { + h: constrainHue(h), + s: b === 1 ? 0 : 1 - w / (1 - b), + v: 1 - b, + a, + }; +} - function snapToInt(num) { - const int = Math.round(num); - return Math.abs(int - num) < 1e-3 ? int : num; - } +function HSVtoHWB({h, s, v, a}) { + return { + h: constrainHue(h), + w: (1 - s) * v * 100, + b: (1 - v) * 100, + a, + }; +} - function hex2(val) { - return (val < 16 ? '0' : '') + Math.round(val).toString(16); - } +export function constrain(min, max, value) { + return value < min ? min : value > max ? max : value; +} - function testAt(rx, index, text) { - if (!rx) return false; - rx.lastIndex = index; - return rx.test(text); - } -})(new Map([ +export function constrainHue(h) { + return h < 0 ? h % 360 + 360 : + h >= 360 ? h % 360 : + h; +} + +export function snapToInt(num) { + const int = Math.round(num); + return Math.abs(int - num) < 1e-3 ? int : num; +} + +function hex2(val) { + return (val < 16 ? '0' : '') + Math.round(val).toString(16); +} + +export function testAt(rx, index, text) { + if (!rx) return false; + rx.lastIndex = index; + return rx.test(text); +} + +export const NAMED_COLORS = new Map([ ['transparent', {r: 0, g: 0, b: 0, a: 0, type: 'rgb'}], ['aliceblue', {r: 240, g: 248, b: 255, type: 'hex'}], ['antiquewhite', {r: 250, g: 235, b: 215, type: 'hex'}], @@ -421,4 +406,4 @@ const colorConverter = (NAMED_COLORS => { ['whitesmoke', {r: 245, g: 245, b: 245, type: 'hex'}], ['yellow', {r: 255, g: 255, b: 0, type: 'hex'}], ['yellowgreen', {r: 154, g: 205, b: 50, type: 'hex'}], -])); +]); diff --git a/src/js/color/color-mimicry.js b/src/js/color/color-mimicry.js index 209c67921ee..473d03a0ace 100644 --- a/src/js/color/color-mimicry.js +++ b/src/js/color/color-mimicry.js @@ -1,15 +1,14 @@ -/* global $create */// dom.js -/* global debounce */// toolbox.js -'use strict'; +import {$create} from '/js/dom'; +import {debounce} from '/js/toolbox'; + +const styleCache = new Map(); -/* exported colorMimicry */ /** * Calculates real color of an element: * colorMimicry(cm.display.gutters, {bg: 'backgroundColor'}) * colorMimicry('input.foo.bar', null, $('some.parent.to.host.the.dummy')) */ -function colorMimicry(el, targets, dummyContainer = document.body) { - const styleCache = colorMimicry.styleCache || (colorMimicry.styleCache = new Map()); +export default function colorMimicry(el, targets, dummyContainer = document.body) { targets = targets || {}; targets.fore = 'color'; const colors = {}; @@ -56,42 +55,47 @@ function colorMimicry(el, targets, dummyContainer = document.body) { } debounce(clearCache); return colors; +} - function blend(base, color) { - const [r, g, b, a = 255] = (color.match(/\d+/g) || []).map(Number); - if (a === 255) { - base.r = r; - base.g = g; - base.b = b; - base.a = 1; - } else if (a) { - const mixedA = 1 - (1 - a / 255) * (1 - base.a); - const q1 = a / 255 / mixedA; - const q2 = base.a * (1 - mixedA) / mixedA; - base.r = Math.round(r * q1 + base.r * q2); - base.g = Math.round(g * q1 + base.g * q2); - base.b = Math.round(b * q1 + base.b * q2); - base.a = mixedA; - } - return isOpaque(base); +function blend(base, color) { + let r, g, b, a; + if (typeof color === 'string') { + [r, g, b, a = 255] = (color.match(/\d+/g) || []).map(Number); + } else { + ({r, g, b, a = 255} = color); } - - // speed-up for sequential invocations within the same event loop cycle - // (we're assuming the invoker doesn't force CSSOM to refresh between the calls) - function getStyle(el) { - let style = styleCache.get(el); - if (!style) { - style = getComputedStyle(el); - styleCache.set(el, style); - } - return style; + if (a === 255) { + base.r = r; + base.g = g; + base.b = b; + base.a = 1; + } else if (a) { + const mixedA = 1 - (1 - a / 255) * (1 - base.a); + const q1 = a / 255 / mixedA; + const q2 = base.a * (1 - mixedA) / mixedA; + base.r = Math.round(r * q1 + base.r * q2); + base.g = Math.round(g * q1 + base.g * q2); + base.b = Math.round(b * q1 + base.b * q2); + base.a = mixedA; } + return isOpaque(base); +} - function clearCache() { - styleCache.clear(); +/** Speed-up for sequential invocations within the same event loop cycle + * (we're assuming the invoker doesn't force CSSOM to refresh between the calls) */ +function getStyle(el) { + let style = styleCache.get(el); + if (!style) { + style = getComputedStyle(el); + styleCache.set(el, style); } + return style; +} - function isOpaque({a}) { - return Math.abs(a - 1) < 1e-3; - } +function clearCache() { + styleCache.clear(); +} + +function isOpaque({a}) { + return Math.abs(a - 1) < 1e-3; } diff --git a/src/js/color/color-picker.js b/src/js/color/color-picker.js index 6d46f3f284c..4edb54c5db2 100644 --- a/src/js/color/color-picker.js +++ b/src/js/color/color-picker.js @@ -1,10 +1,8 @@ -/* global colorConverter */ -/* global colorMimicry */ -'use strict'; +import * as colorConverter from './color-converter'; +import colorMimicry from './color-mimicry'; -(window.CodeMirror ? window.CodeMirror.prototype : window).colorpicker = function () { +export default function ColorPicker(cm) { const {constrain} = colorConverter; - const cm = window.CodeMirror && this; const CSS_PREFIX = 'colorpicker-'; const HUE_COLORS = [ {hex: '#ff0000', start: .0}, @@ -187,7 +185,8 @@ get: () => $inputs[currentFormat].color, }); Object.defineProperty($inputs, 'colorString', { - get: () => currentFormat && colorConverter.format($inputs[currentFormat].color, undefined, {round: true}), + get: () => currentFormat && + colorConverter.format($inputs[currentFormat].color, undefined, {round: true}), }); HUE_COLORS.forEach(color => Object.assign(color, colorConverter.parse(color.hex))); @@ -214,7 +213,8 @@ $root.className = [...$root.classList] .filter(c => !c.startsWith(`${CSS_PREFIX}theme-`)) - .concat(`${CSS_PREFIX}theme-${['dark', 'light'].includes(opt.theme) ? opt.theme : guessTheme()}`) + .concat(CSS_PREFIX + 'theme-' + + (opt.theme === 'dark' || opt.theme === 'light' ? opt.theme : guessTheme())) .join(' '); document.body.appendChild($root); @@ -780,10 +780,16 @@ const maxX = innerWidth - W; const maxY = innerHeight - H; const s = $root.style; - if (!isNaN(L)) s.left = constrain(0, Math.max(0, L <= maxX ? maxX : L - W), L) + 'px'; - else if (!isNaN(R)) s.right = constrain(0, Math.max(0, R <= maxX ? maxX : R - W), R) + 'px'; - if (!isNaN(T)) s.top = constrain(0, Math.max(0, T <= maxY ? maxY : T - H - 20), T) + 'px'; - else if (!isNaN(B)) s.bottom = constrain(0, Math.max(0, B <= maxY ? maxY : B - H - 20), B) + 'px'; + if (!isNaN(L)) { + s.left = constrain(0, Math.max(0, L <= maxX ? maxX : L - W), L) + 'px'; + } else if (!isNaN(R)) { + s.right = constrain(0, Math.max(0, R <= maxX ? maxX : R - W), R) + 'px'; + } + if (!isNaN(T)) { + s.top = constrain(0, Math.max(0, T <= maxY ? maxY : T - H - 20), T) + 'px'; + } else if (!isNaN(B)) { + s.bottom = constrain(0, Math.max(0, B <= maxY ? maxY : B - H - 20), B) + 'px'; + } s.transform = ''; } @@ -857,4 +863,4 @@ } //endregion -}; +} diff --git a/src/js/color/color-view.js b/src/js/color/color-view.js index 8d38de01edb..61e4a366d11 100644 --- a/src/js/color/color-view.js +++ b/src/js/color/color-view.js @@ -1,746 +1,742 @@ -/* global CodeMirror */ -/* global colorConverter */ -'use strict'; - -(() => { - //region Constants - - const COLORVIEW_CLASS = 'colorview'; - const COLORVIEW_SWATCH_CLASS = COLORVIEW_CLASS + '-swatch'; - const COLORVIEW_SWATCH_CSS = `--${COLORVIEW_SWATCH_CLASS}:`; - const CLOSE_POPUP_EVENT = 'close-colorpicker-popup'; - - const {RX_COLOR, testAt} = colorConverter; - const RX_UNSUPPORTED = (s => s && new RegExp(s))([ - !CSS.supports('color', '#abcd') && /#(.{4}){1,2}$/, - !CSS.supports('color', 'hwb(1 0% 0%)') && /^hwb\(/, - !CSS.supports('color', 'rgb(1e2,0,0)') && /\de/, - !CSS.supports('color', 'rgb(1.5,0,0)') && - /^rgba?\((([^,]+,){0,2}[^,]*\.|(\s*\S+\s+){0,2}\S*\.)/, - !CSS.supports('color', 'rgb(1,2,3,.5)') && /[^a]\(([^,]+,){3}/, - !CSS.supports('color', 'rgb(1,2,3,50%)') && /\((([^,]+,){3}|(\s*\S+[\s/]+){3}).*?%/, - !CSS.supports('color', 'rgb(1 2 3 / 1)') && /^[^,]+$/, - !CSS.supports('color', 'hsl(1turn, 2%, 3%)') && /deg|g?rad|turn/, - ].filter(Boolean).map(rx => rx.source).join('|')); - const RX_DETECT = new RegExp('(^|[\\s(){}[\\]:,/"=])' + - '(' + - RX_COLOR.hex.source + '|' + - '(?:(?:rgb|hsl)a?|hwb)(?=\\()|(?:' + [...colorConverter.NAMED_COLORS.keys()].join('|') + ')' + - '(?=[\\s;(){}[\\]/"!]|$)' + - ')', 'gi'); - const RX_DETECT_FUNC = /((rgb|hsl)a?|hwb)\(/iy; - const RX_COMMENT = /\/\*([^*]+|\*(?!\/))*(\*\/|$)/g; - const RX_STYLE = /(?:^|\s)(?:atom|keyword|variable callee|builtin)(?:\s|$)/; - const SPACE1K = ' '.repeat(1000); - - // milliseconds to work on invisible colors per one run - const TIME_BUDGET = 50; - - // on initial paint the view doesn't have a size yet - // so we process the maximum number of lines that can fit in the window - let maxRenderChunkSize = Math.ceil(window.innerHeight / 14); - - //endregion - //region CodeMirror Events - - const CM_EVENTS = { - changes(cm, info) { - colorizeChanges(cm.state.colorpicker, info); - }, - update(cm) { - const textHeight = cm.display.cachedTextHeight; - const height = cm.display.lastWrapHeight; - if (!height || !textHeight) return; - maxRenderChunkSize = Math.max(20, Math.ceil(height / textHeight)); - const state = cm.state.colorpicker; - if (state.colorizeOnUpdate) { - state.colorizeOnUpdate = false; - colorizeAll(state); - } - cm.off('update', CM_EVENTS.update); - }, - mousedown(cm, event) { - const state = cm.state.colorpicker; - const swatch = hitTest(event); - dispatchEvent(new CustomEvent(CLOSE_POPUP_EVENT, { - detail: swatch && state.popup, - })); - if (swatch) { - event.preventDefault(); - openPopupForSwatch(state, swatch); - } - }, - }; - - //endregion - //region ColorSwatch - - const cache = new Set(); - - class ColorSwatch { - constructor(cm, options = {}) { - this.cm = cm; - this.options = options; - this.markersToRemove = []; - this.markersToRepaint = []; - this.popup = cm.colorpicker && cm.colorpicker(); - if (!this.popup) { - delete CM_EVENTS.mousedown; - document.head.appendChild(document.createElement('style')).textContent = ` - .colorview-swatch::before { - cursor: auto; - } - `; - } - this.colorize(); - this.registerEvents(); +import * as colorConverter from '/js/color/color-converter'; +import ColorPicker from '/js/color/color-picker'; +import CodeMirror from 'codemirror'; + +//region Constants + +const COLORVIEW_CLASS = 'colorview'; +const COLORVIEW_SWATCH_CLASS = COLORVIEW_CLASS + '-swatch'; +const COLORVIEW_SWATCH_CSS = `--${COLORVIEW_SWATCH_CLASS}:`; +const CLOSE_POPUP_EVENT = 'close-colorpicker-popup'; + +const {RX_COLOR, testAt} = colorConverter; +const RX_UNSUPPORTED = (s => s && new RegExp(s))([ + !CSS.supports('color', '#abcd') && /#(.{4}){1,2}$/, + !CSS.supports('color', 'hwb(1 0% 0%)') && /^hwb\(/, + !CSS.supports('color', 'rgb(1e2,0,0)') && /\de/, + !CSS.supports('color', 'rgb(1.5,0,0)') && + /^rgba?\((([^,]+,){0,2}[^,]*\.|(\s*\S+\s+){0,2}\S*\.)/, + !CSS.supports('color', 'rgb(1,2,3,.5)') && /[^a]\(([^,]+,){3}/, + !CSS.supports('color', 'rgb(1,2,3,50%)') && /\((([^,]+,){3}|(\s*\S+[\s/]+){3}).*?%/, + !CSS.supports('color', 'rgb(1 2 3 / 1)') && /^[^,]+$/, + !CSS.supports('color', 'hsl(1turn, 2%, 3%)') && /deg|g?rad|turn/, +].filter(Boolean).map(rx => rx.source).join('|')); +const RX_DETECT = new RegExp('(^|[\\s(){}[\\]:,/"=])' + + '(' + + RX_COLOR.hex.source + '|' + + '(?:(?:rgb|hsl)a?|hwb)(?=\\()|(?:' + [...colorConverter.NAMED_COLORS.keys()].join('|') + ')' + + '(?=[\\s;(){}[\\]/"!]|$)' + + ')', 'gi'); +const RX_DETECT_FUNC = /((rgb|hsl)a?|hwb)\(/iy; +const RX_COMMENT = /\/\*([^*]+|\*(?!\/))*(\*\/|$)/g; +const RX_STYLE = /(?:^|\s)(?:atom|keyword|variable callee|builtin)(?:\s|$)/; +const SPACE1K = ' '.repeat(1000); + +// milliseconds to work on invisible colors per one run +const TIME_BUDGET = 50; + +// on initial paint the view doesn't have a size yet +// so we process the maximum number of lines that can fit in the window +let maxRenderChunkSize = Math.ceil(window.innerHeight / 14); + +//endregion +//region CodeMirror Events + +const CM_EVENTS = { + changes(cm, info) { + colorizeChanges(cm.state.colorpicker, info); + }, + update(cm) { + const textHeight = cm.display.cachedTextHeight; + const height = cm.display.lastWrapHeight; + if (!height || !textHeight) return; + maxRenderChunkSize = Math.max(20, Math.ceil(height / textHeight)); + const state = cm.state.colorpicker; + if (state.colorizeOnUpdate) { + state.colorizeOnUpdate = false; + colorizeAll(state); } - - colorize() { - colorizeAll(this); + cm.off('update', CM_EVENTS.update); + }, + mousedown(cm, event) { + const state = cm.state.colorpicker; + const swatch = hitTest(event); + dispatchEvent(new CustomEvent(CLOSE_POPUP_EVENT, { + detail: swatch && state.popup, + })); + if (swatch) { + event.preventDefault(); + openPopupForSwatch(state, swatch); + } + }, +}; + +//endregion +//region ColorSwatch + +const cache = new Set(); + +class ColorSwatch { + constructor(cm, options = {}) { + this.cm = cm; + this.options = options; + this.markersToRemove = []; + this.markersToRepaint = []; + this.popup = ColorPicker(cm); + if (!this.popup) { + delete CM_EVENTS.mousedown; + document.head.appendChild(document.createElement('style')).textContent = ` + .colorview-swatch::before { + cursor: auto; + } + `; } + this.colorize(); + this.registerEvents(); + } - openPopup(color) { - if (this.popup) openPopupForCursor(this, color); - } + colorize() { + colorizeAll(this); + } - registerEvents() { - for (const name in CM_EVENTS) { - this.cm.on(name, CM_EVENTS[name]); - } - } + openPopup(color) { + if (this.popup) openPopupForCursor(this, color); + } - unregisterEvents() { - for (const name in CM_EVENTS) { - this.cm.off(name, CM_EVENTS[name]); - } + registerEvents() { + for (const name in CM_EVENTS) { + this.cm.on(name, CM_EVENTS[name]); } + } - destroy() { - this.unregisterEvents(); - const {cm} = this; - const {curOp} = cm; - if (!curOp) cm.startOperation(); - cm.getAllMarks().forEach(m => m.className === COLORVIEW_CLASS && m.clear()); - if (!curOp) cm.endOperation(); - cm.state.colorpicker = null; + unregisterEvents() { + for (const name in CM_EVENTS) { + this.cm.off(name, CM_EVENTS[name]); } } - //endregion - //region CodeMirror registration + destroy() { + this.unregisterEvents(); + const {cm} = this; + const {curOp} = cm; + if (!curOp) cm.startOperation(); + cm.getAllMarks().forEach(m => m.className === COLORVIEW_CLASS && m.clear()); + if (!curOp) cm.endOperation(); + cm.state.colorpicker = null; + } +} - CodeMirror.defineOption('colorpicker', false, (cm, value, oldValue) => { - if (oldValue && oldValue !== CodeMirror.Init && cm.state.colorpicker) { - cm.state.colorpicker.destroy(); - } - if (value) { - cm.state.colorpicker = new ColorSwatch(cm, value); - } - }); +//endregion +//region CodeMirror registration - CodeMirror.prototype.getStyleAtPos = getStyleAtPos; +CodeMirror.defineOption('colorpicker', false, (cm, value, oldValue) => { + if (oldValue && oldValue !== CodeMirror.Init && cm.state.colorpicker) { + cm.state.colorpicker.destroy(); + } + if (value) { + cm.state.colorpicker = new ColorSwatch(cm, value); + } +}); - return; +CodeMirror.prototype.getStyleAtPos = getStyleAtPos; - //endregion - //region Colorizing +//endregion +//region Colorizing - function colorizeAll(state) { - const {cm} = state; - const {viewFrom, viewTo} = cm.display; - if (!viewTo) { - state.colorizeOnUpdate = true; - return; - } - const {curOp} = cm; - if (!curOp) cm.startOperation(); +function colorizeAll(state) { + const {cm} = state; + const {viewFrom, viewTo} = cm.display; + if (!viewTo) { + state.colorizeOnUpdate = true; + return; + } + const {curOp} = cm; + if (!curOp) cm.startOperation(); - state.line = viewFrom; - state.inComment = null; - state.now = performance.now(); - state.stopAt = state.stopped = null; + state.line = viewFrom; + state.inComment = null; + state.now = performance.now(); + state.stopAt = state.stopped = null; - cm.doc.iter(viewFrom, viewTo, lineHandle => colorizeLine(state, lineHandle)); + cm.doc.iter(viewFrom, viewTo, lineHandle => colorizeLine(state, lineHandle)); - updateMarkers(state); - if (!curOp) cm.endOperation(); + updateMarkers(state); + if (!curOp) cm.endOperation(); - if (viewFrom > 0 || viewTo < cm.doc.size) { - clearTimeout(state.colorizeTimer); - state.line = 0; - state.colorizeTimer = setTimeout(colorizeInvisible, 100, state, viewFrom, viewTo); - } + if (viewFrom > 0 || viewTo < cm.doc.size) { + clearTimeout(state.colorizeTimer); + state.line = 0; + state.colorizeTimer = setTimeout(colorizeInvisible, 100, state, viewFrom, viewTo); } +} - function colorizeInvisible(state, viewFrom, viewTo) { - const {cm} = state; - const {curOp} = cm; - if (!curOp) cm.startOperation(); +function colorizeInvisible(state, viewFrom, viewTo) { + const {cm} = state; + const {curOp} = cm; + if (!curOp) cm.startOperation(); - state.now = performance.now(); - state.stopAt = state.now + TIME_BUDGET; - state.stopped = null; + state.now = performance.now(); + state.stopAt = state.now + TIME_BUDGET; + state.stopped = null; - // before the visible range - cm.eachLine(state.line, viewFrom, lineHandle => colorizeLine(state, lineHandle)); + // before the visible range + cm.eachLine(state.line, viewFrom, lineHandle => colorizeLine(state, lineHandle)); - // after the visible range - if (!state.stopped && viewTo < cm.doc.size) { - state.line = Math.max(viewTo, state.line); - cm.eachLine(state.line, cm.doc.size, lineHandle => colorizeLine(state, lineHandle)); - } + // after the visible range + if (!state.stopped && viewTo < cm.doc.size) { + state.line = Math.max(viewTo, state.line); + cm.eachLine(state.line, cm.doc.size, lineHandle => colorizeLine(state, lineHandle)); + } - updateMarkers(state); - if (!curOp) cm.endOperation(); + updateMarkers(state); + if (!curOp) cm.endOperation(); - if (state.stopped) { - state.colorizeTimer = setTimeout(colorizeInvisible, 0, state, viewFrom, viewTo); - } + if (state.stopped) { + state.colorizeTimer = setTimeout(colorizeInvisible, 0, state, viewFrom, viewTo); } +} - function colorizeChanges(state, changes) { - if (changes.length === 1 && changes[0].origin === 'setValue') { - colorizeAll(state); - return; - } - const queue = []; - const postponed = []; - const viewFrom = state.cm.display.viewFrom || 0; - const viewTo = state.cm.display.viewTo || viewFrom + maxRenderChunkSize; - - for (let change of changes) { - const {from} = change; - const to = CodeMirror.changeEnd(change); - const offscreen = from.line > viewTo || to.line < viewFrom; - if (offscreen) { - postponed.push(change); - continue; - } - if (from.line < viewFrom) { - postponed.push(Object.assign({}, change, {to: {line: viewFrom - 1}})); - change = Object.assign({}, change, {from: {line: viewFrom}}); - } - if (to.line > viewTo) { - postponed.push(Object.assign({}, change, {from: {line: viewTo + 1}})); - change = Object.assign({}, change, {to: {line: viewTo}}); - } - queue.push(change); - } - - if (queue.length) colorizeChangesNow(state, queue); - if (postponed.length) setTimeout(colorizeChangesNow, 0, state, postponed, true); +function colorizeChanges(state, changes) { + if (changes.length === 1 && changes[0].origin === 'setValue') { + colorizeAll(state); + return; + } + const queue = []; + const postponed = []; + const viewFrom = state.cm.display.viewFrom || 0; + const viewTo = state.cm.display.viewTo || viewFrom + maxRenderChunkSize; + + for (let change of changes) { + const {from} = change; + const to = CodeMirror.changeEnd(change); + const offscreen = from.line > viewTo || to.line < viewFrom; + if (offscreen) { + postponed.push(change); + continue; + } + if (from.line < viewFrom) { + postponed.push(Object.assign({}, change, {to: {line: viewFrom - 1}})); + change = Object.assign({}, change, {from: {line: viewFrom}}); + } + if (to.line > viewTo) { + postponed.push(Object.assign({}, change, {from: {line: viewTo + 1}})); + change = Object.assign({}, change, {to: {line: viewTo}}); + } + queue.push(change); } + if (queue.length) colorizeChangesNow(state, queue); + if (postponed.length) setTimeout(colorizeChangesNow, 0, state, postponed, true); +} - function colorizeChangesNow(state, changes, canPostpone) { - const {cm} = state; - const {curOp} = cm; - if (!curOp) cm.startOperation(); - state.now = performance.now(); - const stopAt = canPostpone && state.now + TIME_BUDGET; - let stopped = null; - - let change, changeFromLine; - let changeToLine = -1; - let queueIndex = -1; - - changes = changes.sort((a, b) => a.from.line - b.from.line || a.from.ch - b.from.ch); - const first = changes[0].from.line; - const last = CodeMirror.changeEnd(changes[changes.length - 1]).line; - let line = state.line = first; - - cm.doc.iter(first, last + 1, lineHandle => { - if (line > changeToLine) { - change = changes[++queueIndex]; - if (!change) return true; - changeFromLine = change.from.line; - changeToLine = CodeMirror.changeEnd(change).line; - } - if (changeFromLine <= line && line <= changeToLine) { - state.line = line; - if (!lineHandle.styles) state.cm.getTokenTypeAt({line, ch: 0}); - colorizeLineViaStyles(state, lineHandle); - } - if (canPostpone && (state.now = performance.now()) > stopAt) { - stopped = true; - return true; - } - line++; - }); +function colorizeChangesNow(state, changes, canPostpone) { + const {cm} = state; + const {curOp} = cm; + if (!curOp) cm.startOperation(); - updateMarkers(state); - if (!curOp) cm.endOperation(); + state.now = performance.now(); + const stopAt = canPostpone && state.now + TIME_BUDGET; + let stopped = null; - if (stopped) { - const stoppedInChange = line >= changeFromLine && line < changeToLine; - if (stoppedInChange) { - changes.splice(0, queueIndex); - changes[0] = Object.assign({}, changes[0], {from: {line}}); - } else { - changes.splice(0, queueIndex + 1); - } - state.colorizeTimer = setTimeout(colorizeChangesNow, 0, state, changes, true); - } - } + let change, changeFromLine; + let changeToLine = -1; + let queueIndex = -1; + changes = changes.sort((a, b) => a.from.line - b.from.line || a.from.ch - b.from.ch); + const first = changes[0].from.line; + const last = CodeMirror.changeEnd(changes[changes.length - 1]).line; + let line = state.line = first; - function colorizeLine(state, lineHandle) { - if (state.stopAt && (state.now = performance.now()) > state.stopAt) { - state.stopped = true; - return true; + cm.doc.iter(first, last + 1, lineHandle => { + if (line > changeToLine) { + change = changes[++queueIndex]; + if (!change) return true; + changeFromLine = change.from.line; + changeToLine = CodeMirror.changeEnd(change).line; } - const {text, styles} = lineHandle; - const {cm} = state; - - if (state.inComment === null && !styles) { - cm.getTokenTypeAt({line: state.line, ch: 0}); + if (changeFromLine <= line && line <= changeToLine) { + state.line = line; + if (!lineHandle.styles) state.cm.getTokenTypeAt({line, ch: 0}); colorizeLineViaStyles(state, lineHandle); - return; } - - if (styles) { - colorizeLineViaStyles(state, lineHandle); - return; + if (canPostpone && (state.now = performance.now()) > stopAt) { + stopped = true; + return true; } + line++; + }); - let cmtStart = 0; - let cmtEnd = 0; - do { - if (state.inComment) { - cmtEnd = text.indexOf('*/', cmtStart); - if (cmtEnd < 0) break; - state.inComment = false; - cmtEnd += 2; - } - cmtStart = (text.indexOf('/*', cmtEnd) + 1 || text.length + 1) - 1; - const chunk = !cmtEnd && cmtStart === text.length ? text : text.slice(cmtEnd, cmtStart); - - RX_DETECT.lastIndex = 0; - const m = RX_DETECT.exec(chunk); - if (m) { - cmtEnd += m.index + m[1].length; - cm.getTokenTypeAt({line: state.line, ch: 0}); - const {index} = getStyleAtPos({styles: lineHandle.styles, pos: cmtEnd}) || {}; - colorizeLineViaStyles(state, lineHandle, Math.max(1, index || 0)); - return; - } - state.inComment = cmtStart < text.length; - } while (state.inComment); - state.line++; - } - - - function colorizeLineViaStyles(state, lineHandle, styleIndex = 1) { - const {styles} = lineHandle; - let {text} = lineHandle; - let spanIndex = 0; - let uncommented = false; - let span, style, start, end, len, isHex, isFunc, color; + updateMarkers(state); + if (!curOp) cm.endOperation(); - let {markedSpans} = lineHandle; - let spansSorted = false; - let spansZombies = markedSpans && markedSpans.length; - const spanGeneration = state.now; + if (stopped) { + const stoppedInChange = line >= changeFromLine && line < changeToLine; + if (stoppedInChange) { + changes.splice(0, queueIndex); + changes[0] = Object.assign({}, changes[0], {from: {line}}); + } else { + changes.splice(0, queueIndex + 1); + } + state.colorizeTimer = setTimeout(colorizeChangesNow, 0, state, changes, true); + } +} - // all comments may get blanked out in the loop - const endsWithComment = text.endsWith('*/'); - for (let i = styleIndex; i + 1 < styles.length; i += 2) { - style = styles[i + 1]; - if (!style || !RX_STYLE.test(style)) continue; +function colorizeLine(state, lineHandle) { + if (state.stopAt && (state.now = performance.now()) > state.stopAt) { + state.stopped = true; + return true; + } + const {text, styles} = lineHandle; + const {cm} = state; - start = i > 2 ? styles[i - 2] : 0; - end = styles[i]; - len = end - start; - isHex = text[start] === '#'; - isFunc = text[end] === '('; + if (state.inComment === null && !styles) { + cm.getTokenTypeAt({line: state.line, ch: 0}); + colorizeLineViaStyles(state, lineHandle); + return; + } - if (isFunc && (len < 3 || len > 4 || !testAt(RX_DETECT_FUNC, start, text))) continue; - if (isFunc && !uncommented) { - text = blankOutComments(text, start); - uncommented = true; - } + if (styles) { + colorizeLineViaStyles(state, lineHandle); + return; + } - color = text.slice(start, isFunc ? text.indexOf(')', end) + 1 : end); - const j = !isHex && !isFunc && color.indexOf('!'); - if (j > 0) { - color = color.slice(0, j); - end = start + j; - } - const spanState = markedSpans && checkSpan(); - if (spanState === 'same') continue; - if (checkColor()) { - (spanState ? redeem : mark)(getSafeColorValue()); - } + let cmtStart = 0; + let cmtEnd = 0; + do { + if (state.inComment) { + cmtEnd = text.indexOf('*/', cmtStart); + if (cmtEnd < 0) break; + state.inComment = false; + cmtEnd += 2; + } + cmtStart = (text.indexOf('/*', cmtEnd) + 1 || text.length + 1) - 1; + const chunk = !cmtEnd && cmtStart === text.length ? text : text.slice(cmtEnd, cmtStart); + + RX_DETECT.lastIndex = 0; + const m = RX_DETECT.exec(chunk); + if (m) { + cmtEnd += m.index + m[1].length; + cm.getTokenTypeAt({line: state.line, ch: 0}); + const {index} = getStyleAtPos({styles: lineHandle.styles, pos: cmtEnd}) || {}; + colorizeLineViaStyles(state, lineHandle, Math.max(1, index || 0)); + return; } + state.inComment = cmtStart < text.length; + } while (state.inComment); + state.line++; +} - removeDeadSpans(); - state.inComment = style && style.includes('comment') && !endsWithComment; - state.line++; - return; +function colorizeLineViaStyles(state, lineHandle, styleIndex = 1) { + const {styles} = lineHandle; + let {text} = lineHandle; + let spanIndex = 0; + let uncommented = false; + let span, style, start, end, len, isHex, isFunc, color; - function checkColor() { - if (isHex) return testAt(RX_COLOR.hex, 0, color); - if (!isFunc) return colorConverter.NAMED_COLORS.has(color.toLowerCase()); + let {markedSpans} = lineHandle; + let spansSorted = false; + let spansZombies = markedSpans && markedSpans.length; + const spanGeneration = state.now; - const colorLower = color.toLowerCase(); - if (cache.has(colorLower)) return true; + // all comments may get blanked out in the loop + const endsWithComment = text.endsWith('*/'); - const type = color.substr(0, 3); - const value = color.slice(len + 1, -1); - if (!testAt(RX_COLOR[type], 0, value)) return false; + for (let i = styleIndex; i + 1 < styles.length; i += 2) { + style = styles[i + 1]; + if (!style || !RX_STYLE.test(style)) continue; - cache.add(colorLower); - return true; - } + start = i > 2 ? styles[i - 2] : 0; + end = styles[i]; + len = end - start; + isHex = text[start] === '#'; + isFunc = text[end] === '('; - function mark(colorValue) { - const {line} = state; - state.cm.markText({line, ch: start}, {line, ch: end}, { - className: COLORVIEW_CLASS, - startStyle: COLORVIEW_SWATCH_CLASS, - css: COLORVIEW_SWATCH_CSS + colorValue, - color, - }); + if (isFunc && (len < 3 || len > 4 || !testAt(RX_DETECT_FUNC, start, text))) continue; + if (isFunc && !uncommented) { + text = blankOutComments(text, start); + uncommented = true; } - function getSafeColorValue() { - if (isHex && color.length !== 5 && color.length !== 9) return color; - if (!RX_UNSUPPORTED || !RX_UNSUPPORTED.test(color)) return color; - const value = colorConverter.parse(color); - return colorConverter.format(value, 'rgb'); + color = text.slice(start, isFunc ? text.indexOf(')', end) + 1 : end); + const j = !isHex && !isFunc && color.indexOf('!'); + if (j > 0) { + color = color.slice(0, j); + end = start + j; } - - // update or skip or delete existing swatches - function checkSpan() { - if (!spansSorted) { - markedSpans = markedSpans.sort((a, b) => a.from - b.from); - spansSorted = true; - } - while (spanIndex < markedSpans.length) { - span = markedSpans[spanIndex]; - if (span.from <= start) { - spanIndex++; - } else { - break; - } - if (span.from === start && span.marker.className === COLORVIEW_CLASS) { - spansZombies--; - span.generation = spanGeneration; - const same = color === span.marker.color && - (isFunc || /\W|^$/i.test(text.substr(start + color.length, 1))); - if (same) return 'same'; - state.markersToRemove.push(span.marker); - return 'redeem'; - } - } + const spanState = markedSpans && checkSpan(); + if (spanState === 'same') continue; + if (checkColor()) { + (spanState ? redeem : mark)(getSafeColorValue()); } + } - function redeem(colorValue) { - spansZombies++; - state.markersToRemove.pop(); - state.markersToRepaint.push(span); - span.to = end; - span.line = state.line; - span.index = spanIndex - 1; - span.marker.color = color; - span.marker.css = COLORVIEW_SWATCH_CSS + colorValue; - } + removeDeadSpans(); - function removeDeadSpans() { - if (!spansZombies) return; - for (const span of markedSpans) { - if (span.generation !== spanGeneration && - span.marker.className === COLORVIEW_CLASS) { - state.markersToRemove.push(span.marker); - } - } - } - } + state.inComment = style && style.includes('comment') && !endsWithComment; + state.line++; + return; - //endregion - //region Popup + function checkColor() { + if (isHex) return testAt(RX_COLOR.hex, 0, color); + if (!isFunc) return colorConverter.NAMED_COLORS.has(color.toLowerCase()); - function openPopupForCursor(state, defaultColor) { - const {line, ch} = state.cm.getCursor(); - const lineHandle = state.cm.getLineHandle(line); - const data = { - line, ch, - color: defaultColor, - isShortCut: true, - }; + const colorLower = color.toLowerCase(); + if (cache.has(colorLower)) return true; - let found; - for (const {from, marker} of lineHandle.markedSpans || []) { - if (marker.className === COLORVIEW_CLASS && - from <= ch && ch < from + marker.color.length) { - found = {color: marker.color, ch: from}; - break; - } - } - found = found || findNearestColor(lineHandle, ch); - doOpenPopup(state, Object.assign(data, found)); - if (found) highlightColor(state, data); + const type = color.substr(0, 3); + const value = color.slice(len + 1, -1); + if (!testAt(RX_COLOR[type], 0, value)) return false; + + cache.add(colorLower); + return true; } + function mark(colorValue) { + const {line} = state; + state.cm.markText({line, ch: start}, {line, ch: end}, { + className: COLORVIEW_CLASS, + startStyle: COLORVIEW_SWATCH_CLASS, + css: COLORVIEW_SWATCH_CSS + colorValue, + color, + }); + } - function openPopupForSwatch(state, swatch) { - const cm = state.cm; - const lineDiv = swatch.closest('div'); - const {line: {markedSpans} = {}} = cm.display.renderedView.find(v => v.node === lineDiv) || {}; - if (!markedSpans) return; + function getSafeColorValue() { + if (isHex && color.length !== 5 && color.length !== 9) return color; + if (!RX_UNSUPPORTED || !RX_UNSUPPORTED.test(color)) return color; + const value = colorConverter.parse(color); + return colorConverter.format(value, 'rgb'); + } - let swatchIndex = [...lineDiv.getElementsByClassName(COLORVIEW_SWATCH_CLASS)].indexOf(swatch); - for (const {marker} of markedSpans.sort((a, b) => a.from - b.from)) { - if (marker.className === COLORVIEW_CLASS && swatchIndex-- === 0) { - const data = Object.assign({color: marker.color}, marker.find().from); - highlightColor(state, data); - doOpenPopup(state, data); + // update or skip or delete existing swatches + function checkSpan() { + if (!spansSorted) { + markedSpans = markedSpans.sort((a, b) => a.from - b.from); + spansSorted = true; + } + while (spanIndex < markedSpans.length) { + span = markedSpans[spanIndex]; + if (span.from <= start) { + spanIndex++; + } else { break; } + if (span.from === start && span.marker.className === COLORVIEW_CLASS) { + spansZombies--; + span.generation = spanGeneration; + const same = color === span.marker.color && + (isFunc || /\W|^$/i.test(text.substr(start + color.length, 1))); + if (same) return 'same'; + state.markersToRemove.push(span.marker); + return 'redeem'; + } } } - - function doOpenPopup(state, data) { - const {left, bottom: top} = state.cm.charCoords(data, 'window'); - state.popup.show(Object.assign(state.options.popup, data, { - top, - left, - cm: state.cm, - color: data.color, - prevColor: data.color || '', - callback: popupOnChange, - palette: makePalette(state), - paletteCallback, - })); + function redeem(colorValue) { + spansZombies++; + state.markersToRemove.pop(); + state.markersToRepaint.push(span); + span.to = end; + span.line = state.line; + span.index = spanIndex - 1; + span.marker.color = color; + span.marker.css = COLORVIEW_SWATCH_CSS + colorValue; } - - function popupOnChange(newColor) { - if (!newColor) { - return; + function removeDeadSpans() { + if (!spansZombies) return; + for (const span of markedSpans) { + if (span.generation !== spanGeneration && + span.marker.className === COLORVIEW_CLASS) { + state.markersToRemove.push(span.marker); + } } - const {cm, line, ch, embedderCallback} = this; - const to = {line, ch: ch + this.prevColor.length}; - const from = {line, ch}; - if (cm.getRange(from, to) !== newColor) { - cm.replaceRange(newColor, from, to, '*colorpicker'); - this.prevColor = newColor; + } +} + +//endregion +//region Popup + +function openPopupForCursor(state, defaultColor) { + const {line, ch} = state.cm.getCursor(); + const lineHandle = state.cm.getLineHandle(line); + const data = { + line, ch, + color: defaultColor, + isShortCut: true, + }; + + let found; + for (const {from, marker} of lineHandle.markedSpans || []) { + if (marker.className === COLORVIEW_CLASS && + from <= ch && ch < from + marker.color.length) { + found = {color: marker.color, ch: from}; + break; } - if (typeof embedderCallback === 'function') { - embedderCallback(this); + } + found = found || findNearestColor(lineHandle, ch); + doOpenPopup(state, Object.assign(data, found)); + if (found) highlightColor(state, data); +} + + +function openPopupForSwatch(state, swatch) { + const cm = state.cm; + const lineDiv = swatch.closest('div'); + const {line: {markedSpans} = {}} = cm.display.renderedView.find(v => v.node === lineDiv) || {}; + if (!markedSpans) return; + + let swatchIndex = [...lineDiv.getElementsByClassName(COLORVIEW_SWATCH_CLASS)].indexOf(swatch); + for (const {marker} of markedSpans.sort((a, b) => a.from - b.from)) { + if (marker.className === COLORVIEW_CLASS && swatchIndex-- === 0) { + const data = Object.assign({color: marker.color}, marker.find().from); + highlightColor(state, data); + doOpenPopup(state, data); + break; } } - - function makePalette({cm, options}) { - const palette = new Map(); - let i = 0; - let nums; - cm.eachLine(({markedSpans}) => { - ++i; - if (!markedSpans) return; - for (const {from, marker: m} of markedSpans) { - if (from == null || m.className !== COLORVIEW_CLASS) continue; - const color = m.color.toLowerCase(); - nums = palette.get(color); - if (!nums) palette.set(color, (nums = [])); - nums.push(i); +} + + +function doOpenPopup(state, data) { + const {left, bottom: top} = state.cm.charCoords(data, 'window'); + state.popup.show(Object.assign(state.options.popup, data, { + top, + left, + cm: state.cm, + color: data.color, + prevColor: data.color || '', + callback: popupOnChange, + palette: makePalette(state), + paletteCallback, + })); +} + + +function popupOnChange(newColor) { + if (!newColor) { + return; + } + const {cm, line, ch, embedderCallback} = this; + const to = {line, ch: ch + this.prevColor.length}; + const from = {line, ch}; + if (cm.getRange(from, to) !== newColor) { + cm.replaceRange(newColor, from, to, '*colorpicker'); + this.prevColor = newColor; + } + if (typeof embedderCallback === 'function') { + embedderCallback(this); + } +} + +function makePalette({cm, options}) { + const palette = new Map(); + let i = 0; + let nums; + cm.eachLine(({markedSpans}) => { + ++i; + if (!markedSpans) return; + for (const {from, marker: m} of markedSpans) { + if (from == null || m.className !== COLORVIEW_CLASS) continue; + const color = m.color.toLowerCase(); + nums = palette.get(color); + if (!nums) palette.set(color, (nums = [])); + nums.push(i); + } + }); + const res = []; + if (palette.size > 1 || nums && nums.length > 1) { + const old = new Map((options.popup.palette || []).map(el => [el.__color, el])); + for (const [color, data] of palette) { + const str = data.join(', '); + let el = old.get(color); + if (!el) { + el = document.createElement('div'); + el.__color = color; // also used in color-picker.js + el.className = COLORVIEW_SWATCH_CLASS; + el.style.setProperty(`--${COLORVIEW_SWATCH_CLASS}`, color); } - }); - const res = []; - if (palette.size > 1 || nums && nums.length > 1) { - const old = new Map((options.popup.palette || []).map(el => [el.__color, el])); - for (const [color, data] of palette) { - const str = data.join(', '); - let el = old.get(color); - if (!el) { - el = document.createElement('div'); - el.__color = color; // also used in color-picker.js - el.className = COLORVIEW_SWATCH_CLASS; - el.style.setProperty(`--${COLORVIEW_SWATCH_CLASS}`, color); - } - if (el.__str !== str) { - el.__str = str; - // break down long lists: 10 per line - el.title = `${color}\n${options.popup.paletteLine} ${ - str.length > 50 ? str.replace(/([^,]+,\s){10}/g, '$&\n') : str - }`; - } - res.push(el); + if (el.__str !== str) { + el.__str = str; + // break down long lists: 10 per line + el.title = `${color}\n${options.popup.paletteLine} ${ + str.length > 50 ? str.replace(/([^,]+,\s){10}/g, '$&\n') : str + }`; } - res.push(Object.assign(document.createElement('span'), { - className: 'colorpicker-palette-hint', - title: options.popup.paletteHint, - textContent: '?', - })); + res.push(el); } - return res; + res.push(Object.assign(document.createElement('span'), { + className: 'colorpicker-palette-hint', + title: options.popup.paletteHint, + textContent: '?', + })); } - - function paletteCallback(el) { - const {cm} = this; - const lines = el.title.split('\n')[1].match(/\d+/g).map(Number); - const i = lines.indexOf(cm.getCursor().line + 1) + 1; - const line = (lines[i] || lines[0]) - 1; - cm.jumpToPos({line, ch: 0}); - } - - //endregion - //region Utility - - function updateMarkers(state) { - state.markersToRemove.forEach(m => m.clear()); - state.markersToRemove.length = 0; - - const {cm: {display: {viewFrom, viewTo, view}}} = state; - let viewIndex = 0; - let lineView = view[0]; - let lineViewLine = viewFrom; - for (const {line, index, marker} of state.markersToRepaint) { - if (line < viewFrom || line >= viewTo) continue; - while (lineViewLine < line && lineView) { - lineViewLine += lineView.size; - lineView = view[++viewIndex]; - } - if (!lineView) break; - const el = lineView.text.getElementsByClassName(COLORVIEW_SWATCH_CLASS)[index]; - if (el) el.style = marker.css; - } - state.markersToRepaint.length = 0; + return res; +} + +function paletteCallback(el) { + const {cm} = this; + const lines = el.title.split('\n')[1].match(/\d+/g).map(Number); + const i = lines.indexOf(cm.getCursor().line + 1) + 1; + const line = (lines[i] || lines[0]) - 1; + cm.jumpToPos({line, ch: 0}); +} + +//endregion +//region Utility + +function updateMarkers(state) { + state.markersToRemove.forEach(m => m.clear()); + state.markersToRemove.length = 0; + + const {cm: {display: {viewFrom, viewTo, view}}} = state; + let viewIndex = 0; + let lineView = view[0]; + let lineViewLine = viewFrom; + for (const {line, index, marker} of state.markersToRepaint) { + if (line < viewFrom || line >= viewTo) continue; + while (lineViewLine < line && lineView) { + lineViewLine += lineView.size; + lineView = view[++viewIndex]; + } + if (!lineView) break; + const el = lineView.text.getElementsByClassName(COLORVIEW_SWATCH_CLASS)[index]; + if (el) el.style = marker.css; + } + state.markersToRepaint.length = 0; +} + + +function findNearestColor({styles, text}, pos) { + const ALLOWED_STYLES = ['atom', 'keyword', 'callee', 'comment', 'string']; + let start, color, prevStart, prevColor, m; + RX_DETECT.lastIndex = Math.max(0, pos - 1000); + + while ((m = RX_DETECT.exec(text))) { + start = m.index + m[1].length; + color = getColor(m[2].toLowerCase()); + if (!color) continue; + if (start >= pos) break; + prevStart = start; + prevColor = color; } + if (prevColor && pos - (prevStart + prevColor.length) < start - pos) { + return {color: prevColor, ch: prevStart}; + } else if (color) { + return {color, ch: start}; + } - function findNearestColor({styles, text}, pos) { - const ALLOWED_STYLES = ['atom', 'keyword', 'callee', 'comment', 'string']; - let start, color, prevStart, prevColor, m; - RX_DETECT.lastIndex = Math.max(0, pos - 1000); - - while ((m = RX_DETECT.exec(text))) { - start = m.index + m[1].length; - color = getColor(m[2].toLowerCase()); - if (!color) continue; - if (start >= pos) break; - prevStart = start; - prevColor = color; - } - - if (prevColor && pos - (prevStart + prevColor.length) < start - pos) { - return {color: prevColor, ch: prevStart}; - } else if (color) { - return {color, ch: start}; - } + function getColor(token) { + const {style} = getStyleAtPos({styles, pos: start + 1}) || {}; + const allowed = !style || ALLOWED_STYLES.includes(style.split(' ', 1)[0]); + if (!allowed) return; - function getColor(token) { - const {style} = getStyleAtPos({styles, pos: start + 1}) || {}; - const allowed = !style || ALLOWED_STYLES.includes(style.split(' ', 1)[0]); - if (!allowed) return; - - if (text[start + token.length] === '(') { - const tail = blankOutComments(text.slice(start), 0); - const color = tail.slice(0, tail.indexOf(')') + 1); - const type = color.slice(0, 3); - const value = color.slice(token.length + 1, -1); - return testAt(RX_COLOR[type], 0, value) && color; - } - return (token[0] === '#' || colorConverter.NAMED_COLORS.has(token)) && token; + if (text[start + token.length] === '(') { + const tail = blankOutComments(text.slice(start), 0); + const color = tail.slice(0, tail.indexOf(')') + 1); + const type = color.slice(0, 3); + const value = color.slice(token.length + 1, -1); + return testAt(RX_COLOR[type], 0, value) && color; } + return (token[0] === '#' || colorConverter.NAMED_COLORS.has(token)) && token; } +} - function highlightColor(state, data) { - const {line} = data; - const {cm} = state; - const {viewFrom, viewTo} = cm.display; - if (line < viewFrom || line > viewTo) { - return; - } - const first = cm.charCoords(data); - const colorEnd = data.ch + data.color.length - 1; - let last = cm.charCoords({line, ch: colorEnd}); - if (last.top !== first.top) { - const funcEnd = data.ch + data.color.indexOf('(') - 1; - last = cm.charCoords({line, ch: funcEnd}); - } - const el = document.createElement('div'); - const DURATION_SEC = .5; - el.style = ` - position: absolute; - display: block; - top: ${first.top}px; - left: ${first.left}px; - width: ${last.right - first.left}px; - height: ${last.bottom - first.top}px; - animation: highlight ${DURATION_SEC}s; - `; - document.body.appendChild(el); - setTimeout(() => el.remove(), DURATION_SEC * 1000); - } - - function getStyleAtPos({ - line, - styles = this.getLineHandle(line).styles, - pos, - }) { - if (pos < 0 || !styles) return; - const len = styles.length; - const end = styles[len - 2]; - if (pos > end) return; - if (pos === end) { - return { - style: styles[len - 1], - index: len - 2, - }; - } - const mid = (pos / end * (len - 1) & ~1) + 1; - let a = mid; - let b; - while (a > 1 && styles[a] > pos) { - b = a; - a = (a / 2 & ~1) + 1; - } - if (!b) b = mid; - while (b < len && styles[b] < pos) b = ((len + b) / 2 & ~1) + 1; - while (a < b - 3) { - const c = ((a + b) / 2 & ~1) + 1; - if (styles[c] > pos) b = c; else a = c; - } - while (a < len && styles[a] < pos) a += 2; +function highlightColor(state, data) { + const {line} = data; + const {cm} = state; + const {viewFrom, viewTo} = cm.display; + if (line < viewFrom || line > viewTo) { + return; + } + const first = cm.charCoords(data); + const colorEnd = data.ch + data.color.length - 1; + let last = cm.charCoords({line, ch: colorEnd}); + if (last.top !== first.top) { + const funcEnd = data.ch + data.color.indexOf('(') - 1; + last = cm.charCoords({line, ch: funcEnd}); + } + const el = document.createElement('div'); + const DURATION_SEC = .5; + el.style = ` + position: absolute; + display: block; + top: ${first.top}px; + left: ${first.left}px; + width: ${last.right - first.left}px; + height: ${last.bottom - first.top}px; + animation: highlight ${DURATION_SEC}s; + `; + document.body.appendChild(el); + setTimeout(() => el.remove(), DURATION_SEC * 1000); +} + +function getStyleAtPos({ + line, + styles = this.getLineHandle(line).styles, + pos, +}) { + if (pos < 0 || !styles) return; + const len = styles.length; + const end = styles[len - 2]; + if (pos > end) return; + if (pos === end) { return { - style: styles[a + 1], - index: a, + style: styles[len - 1], + index: len - 2, }; } - - - function blankOutComments(text, start) { - const cmtStart = text.indexOf('/*', start); - return cmtStart < 0 ? text : ( - text.slice(0, cmtStart) + - text.slice(cmtStart) - .replace(RX_COMMENT, s => - SPACE1K.repeat(s.length / 1000 | 0) + SPACE1K.slice(0, s.length % 1000)) - ); + const mid = (pos / end * (len - 1) & ~1) + 1; + let a = mid; + let b; + while (a > 1 && styles[a] > pos) { + b = a; + a = (a / 2 & ~1) + 1; } - - function hitTest({button, target, offsetX, offsetY}) { - if (button) return; - const swatch = target.closest('.' + COLORVIEW_CLASS); - if (!swatch) return; - const {left, width, height} = getComputedStyle(swatch, '::before'); - const bounds = swatch.getBoundingClientRect(); - const swatchClicked = - offsetX >= parseFloat(left) - 1 && - offsetX <= parseFloat(left) + parseFloat(width) + 1 && - offsetY >= parseFloat(height) / 2 - bounds.height / 2 - 1 && - offsetY <= parseFloat(height) / 2 + bounds.height / 2 + 1; - return swatchClicked && swatch; + if (!b) b = mid; + while (b < len && styles[b] < pos) b = ((len + b) / 2 & ~1) + 1; + while (a < b - 3) { + const c = ((a + b) / 2 & ~1) + 1; + if (styles[c] > pos) b = c; else a = c; } - - //endregion -})(); + while (a < len && styles[a] < pos) a += 2; + return { + style: styles[a + 1], + index: a, + }; +} + + +function blankOutComments(text, start) { + const cmtStart = text.indexOf('/*', start); + return cmtStart < 0 ? text : ( + text.slice(0, cmtStart) + + text.slice(cmtStart) + .replace(RX_COMMENT, s => + SPACE1K.repeat(s.length / 1000 | 0) + SPACE1K.slice(0, s.length % 1000)) + ); +} + +function hitTest({button, target, offsetX, offsetY}) { + if (button) return; + const swatch = target.closest('.' + COLORVIEW_CLASS); + if (!swatch) return; + const {left, width, height} = getComputedStyle(swatch, '::before'); + const bounds = swatch.getBoundingClientRect(); + const swatchClicked = + offsetX >= parseFloat(left) - 1 && + offsetX <= parseFloat(left) + parseFloat(width) + 1 && + offsetY >= parseFloat(height) / 2 - bounds.height / 2 - 1 && + offsetY <= parseFloat(height) / 2 + bounds.height / 2 + 1; + return swatchClicked && swatch; +} + +//endregion diff --git a/src/js/csslint/csslint.js b/src/js/csslint/csslint.js index 336f7539394..a5291821199 100644 --- a/src/js/csslint/csslint.js +++ b/src/js/csslint/csslint.js @@ -1,8 +1,8 @@ 'use strict'; const parserlib = typeof self !== 'undefined' - ? (require('/js/csslint/parserlib-base'), self.parserlib) - : require('./parserlib'); + ? (importScripts('/js/csslint/parserlib-base'), self.parserlib) + : importScripts('./parserlib'); //#region Reporter diff --git a/src/js/csslint/parserlib.js b/src/js/csslint/parserlib.js index 9b23bf5a604..6cef9cc98c2 100644 --- a/src/js/csslint/parserlib.js +++ b/src/js/csslint/parserlib.js @@ -5,8 +5,8 @@ //#region Types const parserlib = typeof self !== 'undefined' - ? (require('/js/csslint/parserlib-base'), self.parserlib) - : require('./parserlib-base'); + ? (importScripts('/js/csslint/parserlib-base'), self.parserlib) + : importScripts('./parserlib-base'); const {assign, defineProperty: define} = Object; const { css: { diff --git a/src/js/dlg/config-dialog.js b/src/js/dlg/config-dialog.js index 19b21d1890b..7cb703fad8f 100644 --- a/src/js/dlg/config-dialog.js +++ b/src/js/dlg/config-dialog.js @@ -1,23 +1,16 @@ -/* global $ $create $createLink $remove important messageBoxProxy setupLivePrefs */// dom.js -/* global API */// msg.js -/* global UA UCD clamp debounce deepCopy */// toolbox.js -/* global messageBox */ -/* global prefs */ -/* global t */// localization.js -'use strict'; - -/* exported configDialog */ -async function configDialog(style) { - - await require([ - '/js/color/color-converter', - '/js/color/color-mimicry', - '/js/color/color-picker', - '/js/color/color-picker.css', - '/js/dlg/config-dialog.css', - '/options/onoffswitch.css', - ]); - +import ColorPicker from '/js/color/color-picker'; +import {$, $create, $createLink, $remove, important, setupLivePrefs} from '/js/dom'; +import {t} from '/js/localization'; +import {API} from '/js/msg'; +import * as prefs from '/js/prefs'; +import {clamp, debounce, deepCopy, UA, UCD} from '/js/toolbox'; +import '/js/color/color-converter'; +import messageBox from './message-box'; +import '/js/color/color-picker.css'; +import '/js/dlg/config-dialog.css'; +import '/options/onoffswitch.css'; + +export default function configDialog(style) { const AUTOSAVE_DELAY = 400; let saving = false; let bodyStyle; @@ -31,19 +24,20 @@ async function configDialog(style) { const elements = []; const isInstaller = location.pathname.startsWith('/install-usercss.html'); const isPopup = location.pathname.startsWith('/popup.html'); - const colorpicker = ((window.CodeMirror || {}).prototype || window).colorpicker(); + const colorpicker = ColorPicker(); const buttons = {}; buildConfigForm(); renderValues(); vars.forEach(renderValueState); - return messageBoxProxy.show({ + return messageBox.show({ title: `${style.customName || style.name} v${data.version}`, className: 'config-dialog', contents: [ $create('.config-heading', data.supportURL && - $createLink({className: '.external-support', href: data.supportURL}, t('externalFeedback'))), + $createLink({className: '.external-support', href: data.supportURL}, + t('externalFeedback'))), $create('.config-body', elements), ], buttons: [{ diff --git a/src/js/dlg/message-box.js b/src/js/dlg/message-box.js index f83e66a6f28..e17851357c8 100644 --- a/src/js/dlg/message-box.js +++ b/src/js/dlg/message-box.js @@ -1,17 +1,17 @@ -/* global $ $create animateElement focusA11y moveFocus */// dom.js -/* global clamp */// toolbox.js -/* global t */// localization.js -'use strict'; +import {$, $create, animateElement, focusA11y, moveFocus} from '/js/dom'; +import {t} from '/js/localization'; +import {clamp} from '/js/toolbox'; +import './message-box.css'; // TODO: convert this singleton mess so we can show many boxes at once -/* global messageBox */ -window.messageBox = { +const messageBox = { element: null, listeners: null, _blockScroll: null, _originalFocus: null, _resolve: null, }; +export default messageBox; messageBox.close = async isAnimated => { window.off('keydown', messageBox.listeners.key, true); @@ -44,7 +44,7 @@ messageBox.close = async isAnimated => { * resolves to an object with optionally present properties depending on the interaction: * {button: Number, enter: Boolean, esc: Boolean} */ -messageBox.show = async ({ +messageBox.show = ({ title, contents, className = '', @@ -52,7 +52,6 @@ messageBox.show = async ({ onshow, blockScroll, }) => { - await require(['/js/dlg/message-box.css']); if (!messageBox.listeners) initOwnListeners(); createElement(); bindGlobalListeners(); diff --git a/src/js/dom-base.js b/src/js/dom-base.js index de0aa0942f8..1ef71ad97e2 100644 --- a/src/js/dom-base.js +++ b/src/js/dom-base.js @@ -31,18 +31,6 @@ export const focusA11y = { }, }; -/** - * Autoloads message-box.js - */ -export let messageBoxProxy = new Proxy({}, { - get(_, name) { - return (...args) => Promise.all([ - import('./dlg/message-box'), - require(['/js/dlg/message-box.css']), - ]).then(([m]) => (messageBoxProxy = m.default)[name](...args)); - }, -}); - export function $(selector, base) { // we have ids with . like #manage.onlyEnabled which looks like #id.class // so since getElementById is superfast we'll try it anyway diff --git a/src/js/dom-on-load.js b/src/js/dom-on-load.js index dc507dbf2f4..3ba9dbb104e 100644 --- a/src/js/dom-on-load.js +++ b/src/js/dom-on-load.js @@ -1,13 +1,13 @@ -/* global $$ $ $create focusA11y getEventKeyName moveFocus waitForSelector */// dom.js -/* global CHROME clamp debounce tryURL */// toolbox.js -/* global msg */ -/* global prefs */ -/* global t */// localization.js -'use strict'; +import {$, $$, $create, focusA11y} from './dom-base'; +import {getEventKeyName, moveFocus} from './dom-util'; +import HeaderResizer from './header-resizer'; +import {t} from './localization'; +import {onExtension} from './msg'; +import * as prefs from './prefs'; +import {CHROME, clamp, debounce, tryURL} from './toolbox'; /** DOM housekeeping after a page finished loading */ - -(() => { +export default function DomOnLoad() { const SPLIT_BTN_MENU = '.split-btn-menu'; const tooltips = new WeakMap(); splitLongTooltips(); @@ -19,7 +19,7 @@ window.on('click', splitMenu); window.on('click', interceptClick, true); window.on('resize', () => debounce(addTooltipsToEllipsized, 100)); - msg.onExtension(request => { + onExtension(request => { if (request.method === 'editDeleteText') { document.execCommand('delete'); } @@ -36,7 +36,7 @@ } const elOff = $('#disableAll-label'); // won't hide if already shown if (elOff) prefs.subscribe('disableAll', () => (elOff.dataset.persist = '')); - waitForSelector('#header').then(() => require(['/js/header-resizer'])); + if ($('#header')) HeaderResizer(); const getFSH = DataTransferItem.prototype.getAsFileSystemHandle; if (getFSH) { @@ -195,7 +195,7 @@ const el = event.target.closest('[data-cmd=note]'); if (el) { event.preventDefault(); - window.messageBoxProxy.show({ + window.messageBox.show({ className: 'note center-dialog', contents: tooltips.get(el) || el.title, buttons: [t('confirmClose')], @@ -221,4 +221,4 @@ if (newTitle !== el.title) el.title = newTitle; } } -})(); +} diff --git a/src/js/dom-util.js b/src/js/dom-util.js index 72703fb3505..b96206161d9 100644 --- a/src/js/dom-util.js +++ b/src/js/dom-util.js @@ -1,5 +1,6 @@ import {$, $$, $create, focusA11y, toggleDataset} from './dom-base'; import * as prefs from './prefs'; +import {require} from '/js/toolbox'; /** * @param {HTMLElement} el diff --git a/src/js/dom.js b/src/js/dom.js index a8c8ef2014d..d813bd11339 100644 --- a/src/js/dom.js +++ b/src/js/dom.js @@ -1,424 +1,10 @@ -/* global FIREFOX UA hasOwn */// toolbox.js -/* global prefs */ -'use strict'; - -/* exported - $createLink - $isTextInput - $remove - $$remove - animateElement - focusA11y - getEventKeyName - important - messageBoxProxy - moveFocus - scrollElementIntoView - setInputValue - setupLivePrefs - showSpinner - toggleDataset -*/ - -Object.assign(EventTarget.prototype, { - on: addEventListener, - off: removeEventListener, -}); - -//#region Exports - -$.root = document.documentElement; -$.rootCL = $.root.classList; - -// Makes the focus outline appear on keyboard tabbing, but not on mouse clicks. -const focusA11y = { - // last event's focusedViaClick - lastFocusedViaClick: false, - get: el => el && el.dataset.focusedViaClick != null, - toggle: (el, state) => el && toggleDataset(el, 'focusedViaClick', state), - // to avoid a full layout recalc due to changes on body/root - // we modify the closest focusable element (like input or button or anything with tabindex=0) - closest(el) { - let labelSeen; - for (; el; el = el.parentElement) { - if (el.localName === 'label' && el.control && !labelSeen) { - el = el.control; - labelSeen = true; - } - if (el.tabIndex >= 0) return el; - } - }, -}; - -/** - * Autoloads message-box.js - * @alias messageBox - */ -window.messageBoxProxy = new Proxy({}, { - get(_, name) { - return async (...args) => { - await require([ - '/js/dlg/message-box', /* global messageBox */ - '/js/dlg/message-box.css', - ]); - window.messageBoxProxy = messageBox; - return messageBox[name](...args); - }; - }, -}); - -function $(selector, base) { - // we have ids with . like #manage.onlyEnabled which looks like #id.class - // so since getElementById is superfast we'll try it anyway - const byId = !base && selector.startsWith('#') && document.getElementById(selector.slice(1)); - return byId || (base || document).querySelector(selector); -} - -function $$(selector, base = document) { - return [...base.querySelectorAll(selector)]; -} - -function $isTextInput(el = {}) { - return el.localName === 'textarea' || - el.localName === 'input' && /^(text|search|number)$/.test(el.type); -} - -function $remove(selector, base = document) { - const el = selector && typeof selector === 'string' ? $(selector, base) : selector; - if (el) { - el.remove(); - } -} - -function $$remove(selector, base = document) { - for (const el of base.querySelectorAll(selector)) { - el.remove(); - } -} - -/** - * All parameters are omittable e.g. (), (sel), (props, children), (children) - * All parts of `selector` are optional, tag is 'div' by default. - * `children` is a string (textContent) or Node or array of text/nodes - * `properties` is an object with some special keys: - tag: string, default 'div' - appendChild: element/string or an array of elements/strings - attributes: {'html-case-name': val, ...} via setAttribute - dataset: {camelCaseName: val, ...} via Object.assign - 'data-attr-name': val via setAttribute - 'attr:name': val via setAttribute without prefix - anythingElse: val via el[key] assignment - */ -function $create(selector = 'div', properties, children) { - let tag, opt; - if (typeof selector === 'string') { - if (Array.isArray(properties) || - properties instanceof Node || - typeof properties !== 'object' && children == null) { - opt = {}; - children = properties; - } else { - opt = properties || {}; - children = children || opt.appendChild; - } - const idStart = (selector.indexOf('#') + 1 || selector.length + 1) - 1; - const classStart = (selector.indexOf('.') + 1 || selector.length + 1) - 1; - const id = selector.slice(idStart + 1, classStart); - if (id) { - opt.id = id; - } - const cls = selector.slice(classStart + 1); - if (cls) opt.className = cls.replace(/\./g, ' '); - tag = selector.slice(0, Math.min(idStart, classStart)); - } else if (Array.isArray(selector)) { - tag = 'div'; - opt = {}; - children = selector; - } else { - opt = selector; - tag = opt.tag; - children = opt.appendChild || properties; - } - const element = - tag === 'fragment' ? document.createDocumentFragment() : - document.createElement(tag || 'div'); - for (const child of Array.isArray(children) ? children : [children]) { - if (child) { - element.appendChild(child instanceof Node ? child : document.createTextNode(child)); - } - } - for (const key in opt) { - if (!hasOwn(opt, key)) continue; - const val = opt[key]; - switch (key) { - case 'dataset': - Object.assign(element.dataset, val); - break; - case 'attributes': - if (val) Object.entries(val).forEach(attr => element.setAttribute(...attr)); - break; - case 'style': { - const t = typeof val; - if (t === 'string') element.style.cssText = val; - if (t === 'object') Object.assign(element.style, val); - break; - } - case 'tag': - case 'appendChild': - break; - default: { - if (key.startsWith('attr:')) element.setAttribute(key.slice(5), val); - else if (key.startsWith('data-')) element.setAttribute(key, val); - else element[key] = val; - } - } - } - return element; -} - -function $createLink(href = '', content) { - const opt = { - tag: 'a', - target: '_blank', - rel: 'noopener', - }; - if (typeof href === 'object') { - Object.assign(opt, href); - } else { - opt.href = href; - } - opt.appendChild = opt.appendChild || content; - return $create(opt); -} - -/** - * @param {HTMLElement} el - * @param {string} [cls] - class name that defines or starts an animation - * @param [removeExtraClasses] - class names to remove at animation end in the *same* paint frame, - * which is needed in e.g. Firefox as it may call resolve() in the next frame - * @returns {Promise} - */ -function animateElement(el, cls = 'highlight', ...removeExtraClasses) { - return !el ? Promise.resolve(el) : new Promise(resolve => { - let onDone = () => { - el.classList.remove(cls, ...removeExtraClasses); - onDone = null; - resolve(); - }; - requestAnimationFrame(() => { - if (onDone) { - const style = getComputedStyle(el); - if (style.animationName === 'none' || !parseFloat(style.animationDuration)) { - el.off('animationend', onDone); - onDone(); - } - } - }); - el.on('animationend', onDone, {once: true}); - el.classList.add(cls); - }); -} - -function getEventKeyName(e, letterAsCode) { - const mods = - (e.shiftKey ? 'Shift-' : '') + - (e.ctrlKey ? 'Ctrl-' : '') + - (e.altKey ? 'Alt-' : '') + - (e.metaKey ? 'Meta-' : ''); - return `${ - mods === e.key + '-' ? '' : mods - }${ - e.key - ? !e.key[1] && letterAsCode ? e.code // KeyC - : e.key[1] ? e.key // Esc - : e.key.toUpperCase() // C, Shift-C (single letters we use uppercase for consistency) - : 'Mouse' + ('LMR'[e.button] || e.button) - }`; -} - -function important(str) { - return str.replace(/;/g, '!important;'); -} - -/** - * Switches to the next/previous keyboard-focusable element. - * Doesn't check `visibility` or `display` via getComputedStyle for simplicity. - * @param {HTMLElement} rootElement - * @param {Number} step - for exmaple 1 or -1 (or 0 to focus the first focusable el in the box) - * @returns {HTMLElement|false|undefined} - - * HTMLElement: focus changed, - * false: focus unchanged, - * undefined: nothing to focus - */ -function moveFocus(rootElement, step) { - const elements = [...rootElement.getElementsByTagName('*')]; - const activeEl = document.activeElement; - const activeIndex = step ? Math.max(step < 0 ? 0 : -1, elements.indexOf(activeEl)) : -1; - const num = elements.length; - if (!step) step = 1; - for (let i = 1; i <= num; i++) { - const el = elements[(activeIndex + i * step + num) % num]; - if (!el.disabled && el.tabIndex >= 0 && el.getBoundingClientRect().width) { - el.focus(); - // suppress focus outline when invoked via click - toggleDataset(el, 'focusedViaClick', focusA11y.lastFocusedViaClick); - return activeEl !== el && el; - } - } -} - -/** - * Scrolls `window` or the closest parent with `class="scroller"` if the element is not visible, - * centering the element in the view - * @param {HTMLElement} element - * @param {number} [invalidMarginRatio] - for example, 0.10 will center the element if it's in the top/bottom 10% of the scroller - */ -function scrollElementIntoView(element, {invalidMarginRatio = 0} = {}) { - // align to the top/bottom of the visible area if wasn't visible - if (!element.parentNode) return; - const {top, height} = element.getBoundingClientRect(); - const {top: parentTop, bottom: parentBottom} = element.parentNode.getBoundingClientRect(); - const windowHeight = window.innerHeight; - if (top < Math.max(parentTop, windowHeight * invalidMarginRatio) || - top > Math.min(parentBottom, windowHeight) - height - windowHeight * invalidMarginRatio) { - const scroller = element.closest('.scroller') || window; - scroller.scrollBy(0, top - (scroller.clientHeight || windowHeight) / 2 + height); - } -} - -function setInputValue(input, value) { - input.focus(); - input.select(); - // using execCommand to add to the input's undo history - document.execCommand(value ? 'insertText' : 'delete', false, value); - // some versions of Firefox ignore execCommand - if (input.value !== value) { - input.value = value; - input.dispatchEvent(new Event('input', {bubbles: true})); - } -} - -/** - * Accepts an array of pref names (values are fetched via prefs.get) - * or an element inside which to look for elements with known pref ids - * and establishes a two-way connection between the document elements and the actual prefs - */ -function setupLivePrefs(ids) { - let init = true; - // getElementsByTagName is cached so it's much faster than calling querySelector for each id - const all = (ids instanceof Element ? ids : document).getElementsByTagName('*'); - ids = Array.isArray(ids) ? [...ids] : prefs.knownKeys.filter(id => id in all); - prefs.subscribe(ids, updateElement, true); - init = false; - function onChange() { - if (this.checkValidity() && (this.type !== 'radio' || this.checked)) { - prefs.set(this.id || this.name, getValue(this)); - } - } - function getValue(el) { - const type = el.dataset.valueType || el.type; - return type === 'checkbox' ? el.checked : - type === 'number' ? parseFloat(el.value) : - el.value; - } - function isSame(el, oldValue, value) { - return el.type === 'radio' ? el.checked === (oldValue === value) : - el.localName === 'select' && typeof value === 'boolean' && oldValue === `${value}` || - oldValue === value; - } - function updateElement(id, value) { - const byId = all[id]; - const els = byId && byId.id ? [byId] : document.getElementsByName(id); - if (!els[0]) { - prefs.unsubscribe(id, updateElement); - return; - } - for (const el of els) { - const oldValue = getValue(el); - const diff = !isSame(el, oldValue, value); - if ((init || diff) && el.type === 'select-one' && el.classList.contains('fit-width')) { - fitSelectBox(el, value, init); /* global fitSelectBox */// manage/render.js - } else if (diff) { - if (el.type === 'radio') { - el.checked = value === oldValue; - } else if (el.type === 'checkbox') { - el.checked = value; - } else { - el.value = value; - } - el.dispatchEvent(new Event('change', {bubbles: true})); - } - if (init) el.on('change', onChange); - } - } -} - -/** @param {string|Node} parent - selector or DOM node */ -async function showSpinner(parent) { - await require(['/css/spinner.css']); - parent = parent instanceof Node ? parent : $(parent); - return parent.appendChild($create('.lds-spinner', - new Array(12).fill($create('div')).map(e => e.cloneNode()))); -} - -function toggleDataset(el, prop, state) { - if (!el) return; - const wasEnabled = el.dataset[prop] != null; // avoids mutating DOM unnecessarily - if (state) { - if (!wasEnabled) el.dataset[prop] = ''; - } else { - if (wasEnabled) delete el.dataset[prop]; - } -} - -/** - * @param {string} selector - beware of $ quirks with `#dotted.id` that won't work with $$ - * @param {Object} [opt] - * @param {function(HTMLElement[]):boolean} [opt.recur] - called on each match until stopOnDomReady, - you can also return `false` to disconnect the observer - * @param {boolean} [opt.stopOnDomReady] - stop observing on DOM ready - * @returns {Promise} - resolves on first match - */ -function waitForSelector(selector, {recur, stopOnDomReady = true} = {}) { - let el = $(selector); - let elems; - return el && (!recur || recur(elems = $$(selector)) === false) - ? Promise.resolve(el) - : new Promise(resolve => { - new MutationObserver((mutations, observer) => { - if (!el) el = $(selector); - if (!el) return; - if (!recur || - callRecur(mutations) === false || - stopOnDomReady && document.readyState === 'complete') { - observer.disconnect(); - } - if (resolve) { - resolve(el); - resolve = null; - } - }).observe(document, {childList: true, subtree: true}); - function isMatching(n) { - return n.tagName && (n.matches(selector) || n.firstElementChild && $(selector, n)); - } - function callRecur([m0, m1]) { - // Checking addedNodes if only 1 MutationRecord to skip simple mutations quickly - if (m1 || (m0 = m0.addedNodes)[3] || [].some.call(m0, isMatching)) { - const all = $$(selector); // Using one $$ call instead of ~100 calls for each node - const added = !elems ? all : all.filter(el => !elems.includes(el)); - if (added.length) { - elems = all; - return recur(added); - } - } - } - }); -} - -//#endregion -//#region Internals - -const dom = {}; +import {$, dom} from './dom-base'; +import DomOnLoad from './dom-on-load'; +import {waitForSelector} from './dom-util'; +import * as prefs from './prefs'; +import {FIREFOX, UA} from './toolbox'; +export * from './dom-base'; +export * from './dom-util'; prefs.subscribe('disableAll', (_, val) => { $.rootCL.toggle('all-disabled', val); @@ -451,7 +37,7 @@ prefs.ready.then(() => { } }); -(() => { +{ const cls = (!UA.windows ? 'non-windows ' : '') + (FIREFOX ? 'firefox' : UA.opera ? 'opera' : UA.vivaldi ? 'vivaldi' : ''); if (cls) $.root.className += ' ' + cls; @@ -475,7 +61,5 @@ prefs.ready.then(() => { }); prefs.ready.then(() => dom.setHWProp(prefs.get(HWprefId))); } - window.on('load', () => require(['/js/dom-on-load']), {once: true}); -})(); - -//#endregion + window.on('load', DomOnLoad, {once: true}); +} diff --git a/src/js/header-resizer.js b/src/js/header-resizer.js index 0017b4d4da8..3e37bdef026 100644 --- a/src/js/header-resizer.js +++ b/src/js/header-resizer.js @@ -1,8 +1,7 @@ -/* global $ $$ dom */// dom.js -/* global prefs */ -'use strict'; +import {$, $$, dom} from '/js/dom-base'; +import * as prefs from '/js/prefs'; -(() => { +export default function HeaderResizer() { let curW = $('#header').offsetWidth; let offset, perPage; prefs.subscribe(dom.HWprefId, (key, val) => setWidth(val)); @@ -45,4 +44,4 @@ } } } -})(); +} diff --git a/src/js/jsonlint-bundle.js b/src/js/jsonlint-bundle.js new file mode 100644 index 00000000000..b103af709ef --- /dev/null +++ b/src/js/jsonlint-bundle.js @@ -0,0 +1,3 @@ +import 'codemirror/mode/javascript/javascript'; +import 'codemirror/addon/lint/json-lint'; +import '/vendor/jsonlint/jsonlint'; diff --git a/src/js/localization.js b/src/js/localization.js index dab18f9471b..452de39716b 100644 --- a/src/js/localization.js +++ b/src/js/localization.js @@ -1,6 +1,3 @@ -/* global $$ $ waitForSelector */// dom.js -'use strict'; - /** * - like el.prepend() inserts the text as the first node * - like el.append() inserts the text as the last node @@ -8,14 +5,17 @@ * - creates an attribute `title`, spaces are ignored * */ +import {$, $$} from './dom-base'; +import {waitForSelector} from './dom-util'; -function t(key, params, strict = true) { +export function t(key, params, strict = true) { const s = !params && t.cache[key] || (t.cache[key] = chrome.i18n.getMessage(key, params)); if (!s && strict) throw `Missing string "${key}"`; return s; } +// TODO: export directly Object.assign(t, { cache: {}, onBody: [], @@ -94,10 +94,11 @@ Object.assign(t, { const {content} = el; const toRemove = []; // Compress inter-tag whitespace to reduce DOM tree and avoid space between elements without flex - const walker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT); + const walker = document.createTreeWalker(content, + 4 /*NodeFilter.SHOW_TEXT*/ | 0x80 /*NodeFilter.SHOW_COMMENT*/); for (let n; (n = walker.nextNode());) { if (!/[\xA0\S]/.test(n.textContent) || // allowing \xA0 so as to preserve   - n.nodeType === Node.COMMENT_NODE) { + n.nodeType === 8 /*Node.COMMENT_NODE*/) { toRemove.push(n); } } @@ -183,7 +184,10 @@ Object.assign(t, { const newDate = new Date(Number(date) || date); const needsYear = newDate.getYear() !== now.getYear(); const needsWeekDay = needsTime && (now - newDate <= 7 * 24 * 3600e3); - const intlKey = `_intl${needsWeekDay ? 'W' : ''}${needsYear ? 'Y' : ''}${needsTime ? 'HM' : ''}`; + const intlKey = '_intl' + + (needsWeekDay ? 'W' : '') + + (needsYear ? 'Y' : '') + + (needsTime ? 'HM' : ''); const intl = t[intlKey] || (t[intlKey] = new Intl.DateTimeFormat([chrome.i18n.getUILanguage(), 'en'], { day: 'numeric', diff --git a/src/js/meta-parser.js b/src/js/meta-parser.js index 49eb26eebb4..5705aada8eb 100644 --- a/src/js/meta-parser.js +++ b/src/js/meta-parser.js @@ -1,8 +1,7 @@ 'use strict'; -/* exported metaParser */ -const metaParser = (() => { - require(['/vendor/usercss-meta/usercss-meta']); /* global usercssMeta */ +self.metaParser = (() => { + importScripts('/vendor/usercss-meta/usercss-meta'); /* global usercssMeta */ const {createParser, ParseError} = usercssMeta; const PREPROCESSORS = new Set(['default', 'uso', 'stylus', 'less']); const options = { @@ -27,7 +26,7 @@ const metaParser = (() => { } }, color: state => { - require(['/js/color/color-converter']); /* global colorConverter */ + importScripts('/js/color/color-converter'); /* global colorConverter */ const color = colorConverter.parse(state.value); if (!color) { throw new ParseError({ diff --git a/src/js/moz-parser.js b/src/js/moz-parser.js index 70e45abcbc3..d7098544841 100644 --- a/src/js/moz-parser.js +++ b/src/js/moz-parser.js @@ -1,9 +1,9 @@ 'use strict'; -require([ +importScripts( '/js/csslint/parserlib', /* global parserlib */ '/js/sections-util', /* global MozDocMapper */ -]); +); /* exported extractSections */ /** @@ -43,7 +43,7 @@ function extractSections({code, styleId, fast = true}) { }; // move last comment before @-moz-document inside the section if (!lastCmt.includes('AGENT_SHEET') && - !/==userstyle==/i.test(lastCmt)) { + !/==userstyle==/i.test(lastCmt)) { if (lastCmt) { section.code = lastCmt + '\n'; outerText = outerText.slice(0, -lastCmt.length); diff --git a/src/js/msg-base.js b/src/js/msg-base.js new file mode 100644 index 00000000000..9cefa93b4ed --- /dev/null +++ b/src/js/msg-base.js @@ -0,0 +1,158 @@ +/* global TDM */// apply.js - used only in non-bg context + +const TARGETS = { + __proto: null, + all: ['both', 'tab', 'extension'], + extension: ['both', 'extension'], + tab: ['both', 'tab'], +}; +const handler = { + both: new Set(), + tab: new Set(), + extension: new Set(), +}; +const rxIgnorableError = /Receiving end does not exist|The message port closed|moved into back\/forward cache/; +const saveStack = () => new Error(); // Saving callstack prior to `await` +const portReqs = {}; + +let bgReadySignal; +let bgReadying = new Promise(fn => (bgReadySignal = fn)); +let msgId = 0; +/** @type {chrome.runtime.Port} */ +let port; + +// TODO: maybe move into browser.js and hook addListener to wrap/unwrap automatically +chrome.runtime.onMessage.addListener(onRuntimeMessage); + +export function on(fn) { + handler.both.add(fn); +} + +export function onTab(fn) { + handler.tab.add(fn); +} + +export function onExtension(fn) { + handler.extension.add(fn); +} + +export function off(fn) { + for (const type of TARGETS.all) { + handler[type].delete(fn); + } +} + +export function _execute(target, ...args) { + let result; + for (const type of TARGETS[target] || TARGETS.all) { + for (const fn of handler[type]) { + let res; + try { + res = fn(...args); + } catch (err) { + res = Promise.reject(err); + } + if (res !== undefined && result === undefined) { + result = res; + } + } + } + return result; +} + +async function apiSend(data) { + const id = ++msgId; + const err = saveStack(); + if (!port) { + port = chrome.runtime.connect({name: 'api'}); + port.onMessage.addListener(apiPortResponse); + port.onDisconnect.addListener(apiPortDisconnect); + } + port.postMessage({id, data, TDM}); + return new Promise((ok, ko) => (portReqs[id] = {ok, ko, err})); +} + +export function apiPortDisconnect() { + const error = chrome.runtime.lastError; + if (error) for (const id in portReqs) apiPortResponse({id, error}); + port = null; +} + +function apiPortResponse({id, data, error}) { + const req = portReqs[id]; + delete portReqs[id]; + if (error) { + const {err} = req; + err.message = error.message; + if (error.stack) err.stack = error.stack + '\n' + err.stack; + req.ko(error); + } else { + req.ok(data); + } +} + +export function onRuntimeMessage({data, target}, sender, sendResponse) { + if (data.method === 'backgroundReady') { + if (bgReadySignal) bgReadySignal(true); + if (port) apiPortDisconnect(); + } + const res = _execute(target, data, sender); + if (res instanceof Promise) { + res.then(wrapData, wrapError).then(sendResponse); + return true; + } + if (res !== undefined) sendResponse(wrapData(res)); +} + +export async function unwrap(promise) { + const err = saveStack(); + let data, error; + try { + ({data, error} = await promise || {}); + } catch (e) { + error = e; + } + if (!error || rxIgnorableError.test(err.message = error.message)) { + return data; + } + if (error.stack) err.stack = error.stack + '\n' + err.stack; + return Promise.reject(err); +} + +function wrapData(data) { + return {data}; +} + +export function wrapError(error) { + return { + error: Object.assign({ + message: error.message || `${error}`, + stack: error.stack, + }, error), // passing custom properties e.g. `error.index` + }; +} + +async function sendRetry(m) { + try { + return await apiSend(m); + } catch (e) { + return bgReadying && rxIgnorableError.test(e.message) + ? await bgReadying && apiSend(m) + : Promise.reject(e); + } finally { + // Assuming bg is ready if messaging succeeded + bgReadying = bgReadySignal = null; + } +} + +export const apiHandler = __ENTRY !== 'background' && { + get: ({name: path}, name) => new Proxy( + Object.defineProperty(() => {}, 'name', {value: path ? path + '.' + name : name}), + apiHandler), + apply: ({name: path}, thisObj, args) => + (bgReadying ? sendRetry : apiSend)({method: 'invokeAPI', path, args}), +}; + +export const API = __ENTRY === 'background' + ? self.API + : self.API = new Proxy({path: ''}, apiHandler); diff --git a/src/js/msg.js b/src/js/msg.js index 3461e1af746..6f8edbd1354 100644 --- a/src/js/msg.js +++ b/src/js/msg.js @@ -1,178 +1,39 @@ -/* global TDM */// apply.js - used only in non-bg context -'use strict'; - -(() => { - if (window.INJECTED === 1) return; - - const TARGETS = Object.assign(Object.create(null), { - all: ['both', 'tab', 'extension'], - extension: ['both', 'extension'], - tab: ['both', 'tab'], - }); - const handler = { - both: new Set(), - tab: new Set(), - extension: new Set(), - }; - const loadBg = () => browser.runtime.getBackgroundPage().catch(() => false); - const rxIgnorableError = /Receiving end does not exist|The message port closed|moved into back\/forward cache/; - const saveStack = () => new Error(); // Saving callstack prior to `await` - - const portReqs = {}; - let bgReadySignal; - let bgReadying = new Promise(fn => (bgReadySignal = fn)); - let msgId = 0; - /** @type {chrome.runtime.Port} */ - let port; - - // TODO: maybe move into browser.js and hook addListener to wrap/unwrap automatically - chrome.runtime.onMessage.addListener(onRuntimeMessage); - - /* In chrome-extension:// context `window.msg` is created earlier by another script, - * while in a content script it's not, but may exist anyway due to a DOM node with id="msg", - * so we check chrome.tabs first to decide whether we can reuse the existing object. */ - const msg = Object.assign(chrome.tabs ? window.msg : window.msg = {}, /** @namespace msg */ { - - on(fn) { - handler.both.add(fn); - }, - - onTab(fn) { - handler.tab.add(fn); - }, - - onExtension(fn) { - handler.extension.add(fn); - }, - - off(fn) { - for (const type of TARGETS.all) { - handler[type].delete(fn); - } - }, - - _execute(target, ...args) { - let result; - for (const type of TARGETS[target] || TARGETS.all) { - for (const fn of handler[type]) { - let res; - try { - res = fn(...args); - } catch (err) { - res = Promise.reject(err); - } - if (res !== undefined && result === undefined) { - result = res; - } - } - } - return result; - }, - _disconnectApi: apiPortDisconnect, - _unwrap: unwrap, - _wrapError: wrapError, - }); - - async function apiSend(data) { - const id = ++msgId; - const err = saveStack(); - if (!port) { - port = chrome.runtime.connect({name: 'api'}); - port.onMessage.addListener(apiPortResponse); - port.onDisconnect.addListener(apiPortDisconnect); - } - port.postMessage({id, data, TDM}); - return new Promise((ok, ko) => (portReqs[id] = {ok, ko, err})); - } - - function apiPortDisconnect() { - const error = chrome.runtime.lastError; - if (error) for (const id in portReqs) apiPortResponse({id, error}); - port = null; - } - - function apiPortResponse({id, data, error}) { - const req = portReqs[id]; - delete portReqs[id]; - if (error) { - const {err} = req; - err.message = error.message; - if (error.stack) err.stack = error.stack + '\n' + err.stack; - req.ko(error); - } else { - req.ok(data); - } - } - - function onRuntimeMessage({data, target}, sender, sendResponse) { - if (data.method === 'backgroundReady') { - if (bgReadySignal) bgReadySignal(true); - if (port) apiPortDisconnect(); - } - const res = msg._execute(target, data, sender); - if (res instanceof Promise) { - res.then(wrapData, wrapError).then(sendResponse); - return true; - } - if (res !== undefined) sendResponse(wrapData(res)); - } - - async function unwrap(promise) { - const err = saveStack(); - let data, error; - try { - ({data, error} = await promise || {}); - } catch (e) { - error = e; - } - if (!error || rxIgnorableError.test(err.message = error.message)) { - return data; - } - if (error.stack) err.stack = error.stack + '\n' + err.stack; - return Promise.reject(err); - } - - function wrapData(data) { - return {data}; - } - - function wrapError(error) { - return { - error: Object.assign({ - message: error.message || `${error}`, - stack: error.stack, - }, error), // passing custom properties e.g. `error.index` - }; - } - - async function sendRetry(m) { - try { - return await apiSend(m); - } catch (e) { - return bgReadying && rxIgnorableError.test(e.message) - ? await bgReadying && apiSend(m) - : Promise.reject(e); - } finally { - // Assuming bg is ready if messaging succeeded - bgReadying = bgReadySignal = null; - } - } - - if (msg.bg === window) return; - - const apiHandler = { - get({path}, name) { - const fn = () => {}; - fn.path = path ? path + '.' + name : name; - return new Proxy(fn, apiHandler); - }, - async apply({path}, thisObj, args) { - const {bg = msg.bg = chrome.tabs && await loadBg() || false} = msg; - const message = {method: 'invokeAPI', path, args}; - return bg && ((bg.msg || {}).ready || await bg.bgReady.all) ? msg.invokeAPI(path, message) - : bgReadying ? sendRetry(message) - : apiSend(message); - }, +import browser from './browser'; +import {apiHandler, unwrap} from './msg-base'; +import {deepCopy, getOwnTab} from './toolbox'; + +export * from './msg-base'; + +const needsTab = [ + 'updateIconBadge', + 'styleViaAPI', +]; + +export let bg = __ENTRY === 'background' ? self : chrome.extension.getBackgroundPage(); + +async function invokeAPI(path, args) { + let tab = false; + // Using a fake id for our Options frame as we want to fetch styles early + const frameId = window === top ? 0 : 1; + if (!needsTab.includes(path) || !frameId && (tab = await getOwnTab())) { + const res = await bg.msg._execute('extension', + bg.deepCopy({method: 'invokeAPI', path, args}), + bg.deepCopy({url: location.href, tab, frameId})); + return deepCopy(res); + } +} + +export function sendTab(tabId, data, options, target = 'tab') { + return unwrap(browser.tabs.sendMessage(tabId, {data, target}, options)); +} + +if (__ENTRY !== 'background') { + const {apply} = apiHandler; + apiHandler.apply = async (fn, thisObj, args) => { + if (bg === null) bg = await browser.runtime.getBackgroundPage().catch(() => {}) || false; + const bgReady = bg?.bgReady; + return bgReady && (bg.msg || await bgReady.all) + ? invokeAPI(fn.name, args) + : apply(fn, thisObj, args); }; - window.API = /** @type {API} */ new Proxy({path: ''}, apiHandler); -})(); +} diff --git a/src/js/popup-get-styles.js b/src/js/popup-get-styles.js index 3398cc745f5..619b1dce8e6 100644 --- a/src/js/popup-get-styles.js +++ b/src/js/popup-get-styles.js @@ -1,13 +1,13 @@ -/* global API msg */// msg.js -/* global CHROME URLS getActiveTab */// toolbox.js -'use strict'; +import browser from '/js/browser'; +import * as msg from '/js/msg'; +import {API} from '/js/msg'; +import {getActiveTab, URLS} from '/js/toolbox'; -const ABOUT_BLANK = 'about:blank'; +export const ABOUT_BLANK = 'about:blank'; -/* exported popupGetStyles */ -async function popupGetStyles() { +export default async function popupGetStyles() { let tab = await getActiveTab(); - if (!CHROME && tab.status === 'loading' && tab.url === ABOUT_BLANK) { + if (FIREFOX && tab.status === 'loading' && tab.url === ABOUT_BLANK) { tab = await API.waitForTabUrl(tab.id); } let url = tab.pendingUrl || tab.url || ''; // new Chrome uses pendingUrl while connecting diff --git a/src/js/prefs.js b/src/js/prefs.js index 2779978ddd3..a17e54d2d23 100644 --- a/src/js/prefs.js +++ b/src/js/prefs.js @@ -1,260 +1,257 @@ -/* global API msg */// msg.js -/* global deepCopy deepEqual */// toolbox.js -'use strict'; - /** Don't use this file in content script context! */ +import {API, bg} from '/js/msg'; +import {deepCopy, deepEqual} from './toolbox'; -(() => { - /** - * @type PrefsValues - * @namespace PrefsValues - */ - const defaults = { - __proto__: null, - // TODO: sort everything aphabetically - 'openEditInWindow': false, // new editor opens in a own browser window - 'openEditInWindow.popup': false, // new editor opens in a simplified browser window without omnibox - 'windowPosition': {}, // detached window position - 'show-badge': true, // display text on popup menu icon - 'disableAll': false, // boss key - 'exposeIframes': false, // Add 'stylus-iframe' attribute to HTML element in all iframes - 'exposeStyleName': false, // Add style name to the style for better devtools experience - 'newStyleAsUsercss': false, // create new style in usercss format - 'styleViaASS': false, // document.adoptedStyleSheets - 'styleViaXhr': false, // early style injection to avoid FOUC - 'patchCsp': false, // add data: and popular image hosting sites to strict CSP - 'urlInstaller': true, // auto-open installer page for supported .user.css urls - - // checkbox in style config dialog - 'config.autosave': true, +let busy, setReady; - 'schemeSwitcher.enabled': 'system', - 'schemeSwitcher.nightStart': '18:00', - 'schemeSwitcher.nightEnd': '06:00', +/** + * @type PrefsValues + * @namespace PrefsValues + */ +const defaults = { + __proto__: null, + // TODO: sort everything aphabetically + 'openEditInWindow': false, // new editor opens in a own browser window + 'openEditInWindow.popup': false, // new editor opens in a simplified browser window without omnibox + 'windowPosition': {}, // detached window position + 'show-badge': true, // display text on popup menu icon + 'disableAll': false, // boss key + 'exposeIframes': false, // Add 'stylus-iframe' attribute to HTML element in all iframes + 'exposeStyleName': false, // Add style name to the style for better devtools experience + 'newStyleAsUsercss': false, // create new style in usercss format + 'styleViaASS': false, // document.adoptedStyleSheets + 'styleViaXhr': false, // early style injection to avoid FOUC + 'patchCsp': false, // add data: and popular image hosting sites to strict CSP + 'urlInstaller': true, // auto-open installer page for supported .user.css urls - 'popup.enabledFirst': true, // display enabled styles before disabled styles - 'popup.stylesFirst': true, // display enabled styles before disabled styles - 'popup.autoResort': false, // auto re-sort styles after toggling - 'popup.borders': false, // add white borders on the sides - /** @type {'n' | 'u' | 't' | 'w' | 'r'} see IndexEntry */ - 'popup.findSort': 'w', // the inline style search sort order + // checkbox in style config dialog + 'config.autosave': true, - 'manage.onlyEnabled': false, // display only enabled styles - 'manage.onlyLocal': false, // display only styles created locally - 'manage.onlyUsercss': false, // display only usercss styles - 'manage.onlyEnabled.invert': false, // display only disabled styles - 'manage.onlyLocal.invert': false, // display only externally installed styles - 'manage.onlyUsercss.invert': false, // display only non-usercss (standard) styles - // UI element state: expanded/collapsed - 'manage.actions.expanded': true, - 'manage.backup.expanded': true, - 'manage.filters.expanded': true, - 'manage.minColumnWidth': 750, - // the new compact layout doesn't look good on Android yet - 'manage.newUI': true, - 'manage.newUI.favicons': true, // show favicons for the sites in applies-to - 'manage.newUI.faviconsGray': false, // gray out favicons - 'manage.newUI.targets': 3, // max number of applies-to targets visible: 0 = none - 'manage.newUI.sort': 'title,asc', - 'manage.searchMode': 'meta', + 'schemeSwitcher.enabled': 'system', + 'schemeSwitcher.nightStart': '18:00', + 'schemeSwitcher.nightEnd': '06:00', - 'editor.options': {}, // CodeMirror.defaults.* - 'editor.toc.expanded': true, // UI element state: expanded/collapsed - 'editor.options.expanded': true, // UI element state: expanded/collapsed - 'editor.lint.expanded': true, // UI element state: expanded/collapsed - 'editor.publish.expanded': true, // UI element state expanded/collapsed - 'editor.lineWrapping': true, // word wrap - 'editor.smartIndent': true, // 'smart' indent - 'editor.indentWithTabs': false, // smart indent with tabs - 'editor.tabSize': 4, // tab width, in spaces - 'editor.keyMap': 'default', - 'editor.theme': 'default', // CSS theme - // CSS beautifier - 'editor.beautify': { - selector_separator_newline: true, - newline_before_open_brace: false, - newline_after_open_brace: true, - newline_between_properties: true, - newline_before_close_brace: true, - newline_between_rules: false, - preserve_newlines: true, - end_with_newline: false, - indent_conditional: true, - indent_mozdoc: true, - space_around_combinator: true, - space_around_cmp: false, - }, - 'editor.beautify.hotkey': '', - 'editor.lintDelay': 300, // lint gutter marker update delay, ms - 'editor.linter': 'csslint', // 'csslint' or 'stylelint' or '' - 'editor.lintReportDelay': 500, // lint report update delay, ms - 'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected - // selection = only when something is selected - // '' (empty string) = disabled - 'editor.autoCloseBrackets': true, // auto-add a closing pair when typing an opening one of ()[]{}''"" - 'editor.autocompleteOnTyping': false, // show autocomplete dropdown on typing a word token - // "Delete" item in context menu for browsers that don't have it - 'editor.contextDelete': false, - 'editor.selectByTokens': true, - 'editor.arrowKeysTraverse': true, - 'editor.appliesToLineWidget': true, // show applies-to line widget on the editor - 'editor.autosaveDraft': 10, // seconds - 'editor.livePreview': true, - 'editor.livePreview.delay': .2, // seconds (Chrome devtools uses 200ms) - 'editor.targetsFirst': true, + 'popup.enabledFirst': true, // display enabled styles before disabled styles + 'popup.stylesFirst': true, // display enabled styles before disabled styles + 'popup.autoResort': false, // auto re-sort styles after toggling + 'popup.borders': false, // add white borders on the sides + /** @type {'n' | 'u' | 't' | 'w' | 'r'} see IndexEntry */ + 'popup.findSort': 'w', // the inline style search sort order - // show CSS colors as clickable colored rectangles - 'editor.colorpicker': true, - // #DEAD or #beef - 'editor.colorpicker.hexUppercase': false, - // default hotkey - 'editor.colorpicker.hotkey': '', - // last color - 'editor.colorpicker.color': '', - 'editor.colorpicker.maxHeight': 300, + 'manage.onlyEnabled': false, // display only enabled styles + 'manage.onlyLocal': false, // display only styles created locally + 'manage.onlyUsercss': false, // display only usercss styles + 'manage.onlyEnabled.invert': false, // display only disabled styles + 'manage.onlyLocal.invert': false, // display only externally installed styles + 'manage.onlyUsercss.invert': false, // display only non-usercss (standard) styles + // UI element state: expanded/collapsed + 'manage.actions.expanded': true, + 'manage.backup.expanded': true, + 'manage.filters.expanded': true, + 'manage.minColumnWidth': 750, + // the new compact layout doesn't look good on Android yet + 'manage.newUI': true, + 'manage.newUI.favicons': true, // show favicons for the sites in applies-to + 'manage.newUI.faviconsGray': false, // gray out favicons + 'manage.newUI.targets': 3, // max number of applies-to targets visible: 0 = none + 'manage.newUI.sort': 'title,asc', + 'manage.searchMode': 'meta', - // Firefox-only chrome.commands.update - 'hotkey._execute_browser_action': '', - 'hotkey.openManage': '', - 'hotkey.styleDisableAll': '', + 'editor.options': {}, // CodeMirror.defaults.* + 'editor.toc.expanded': true, // UI element state: expanded/collapsed + 'editor.options.expanded': true, // UI element state: expanded/collapsed + 'editor.lint.expanded': true, // UI element state: expanded/collapsed + 'editor.publish.expanded': true, // UI element state expanded/collapsed + 'editor.lineWrapping': true, // word wrap + 'editor.smartIndent': true, // 'smart' indent + 'editor.indentWithTabs': false, // smart indent with tabs + 'editor.tabSize': 4, // tab width, in spaces + 'editor.keyMap': 'default', + 'editor.theme': 'default', // CSS theme + // CSS beautifier + 'editor.beautify': { + selector_separator_newline: true, + newline_before_open_brace: false, + newline_after_open_brace: true, + newline_between_properties: true, + newline_before_close_brace: true, + newline_between_rules: false, + preserve_newlines: true, + end_with_newline: false, + indent_conditional: true, + indent_mozdoc: true, + space_around_combinator: true, + space_around_cmp: false, + }, + 'editor.beautify.hotkey': '', + 'editor.lintDelay': 300, // lint gutter marker update delay, ms + 'editor.linter': 'csslint', // 'csslint' or 'stylelint' or '' + 'editor.lintReportDelay': 500, // lint report update delay, ms + 'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected + // selection = only when something is selected + // '' (empty string) = disabled + 'editor.autoCloseBrackets': true, // auto-add a closing pair when typing an opening one of ()[]{}''"" + 'editor.autocompleteOnTyping': false, // show autocomplete dropdown on typing a word token + // "Delete" item in context menu for browsers that don't have it + 'editor.contextDelete': false, + 'editor.selectByTokens': true, + 'editor.arrowKeysTraverse': true, + 'editor.appliesToLineWidget': true, // show applies-to line widget on the editor + 'editor.autosaveDraft': 10, // seconds + 'editor.livePreview': true, + 'editor.livePreview.delay': .2, // seconds (Chrome devtools uses 200ms) + 'editor.targetsFirst': true, - 'sync.enabled': 'none', + // show CSS colors as clickable colored rectangles + 'editor.colorpicker': true, + // #DEAD or #beef + 'editor.colorpicker.hexUppercase': false, + // default hotkey + 'editor.colorpicker.hotkey': '', + // last color + 'editor.colorpicker.color': '', + 'editor.colorpicker.maxHeight': 300, - 'iconset': -1, // 0 = dark-themed icon - // 1 = light-themed icon - // -1 = match dark/light mode - 'badgeDisabled': '#8B0000', // badge background color when disabled - 'badgeNormal': '#006666', // badge background color + // Firefox-only chrome.commands.update + 'hotkey._execute_browser_action': '', + 'hotkey.openManage': '', + 'hotkey.styleDisableAll': '', - /* Using separate values instead of a single {} to ensure type control. - * Sub-key is the first word in the html's file name. */ - 'headerWidth.edit': 280, - 'headerWidth.install': 280, - 'headerWidth.manage': 280, + 'sync.enabled': 'none', - 'popup.search.globals': false, + 'iconset': -1, // 0 = dark-themed icon + // 1 = light-themed icon + // -1 = match dark/light mode + 'badgeDisabled': '#8B0000', // badge background color when disabled + 'badgeNormal': '#006666', // badge background color - 'popupWidth': 246, // popup width in pixels - 'popupWidthMax': 280, // popup width in pixels + /* Using separate values instead of a single {} to ensure type control. + * Sub-key is the first word in the html's file name. */ + 'headerWidth.edit': 280, + 'headerWidth.install': 280, + 'headerWidth.manage': 280, - 'updateInterval': 24, // user-style automatic update interval, hours (0 = disable) - 'updateOnlyEnabled': false, - }; - const warnUnknown = console.warn.bind(console, 'Unknown preference "%s"'); - /** @type {PrefsValues} */ - const values = deepCopy(defaults); - const onChange = {}; - const isBg = msg.bg === window; - // A scoped listener won't trigger for our [big] stuff in `local`, Chrome 73+, FF - const onSync = chrome.storage.sync.onChanged; - let busy, setReady; - if (isBg) { - busy = new Promise(cb => (setReady = cb)); - busy.set = (...args) => setReady(setAll(...args)); - } else if (window === parent) { - busy = API.prefs.get().then(setAll); - } else { - setAll(deepCopy(parent.prefs.__values)); // using deepCopy of this realm - } - (onSync || chrome.storage.onChanged).addListener((changes, area) => { - if (busy) return; - // eslint-disable-next-line no-use-before-define - const data = (onSync || area === 'sync') && changes[prefs.STORAGE_KEY]; - if (data) setAll(data.newValue, data.oldValue); - }); + 'popup.search.globals': false, - const prefs = window.prefs = { - STORAGE_KEY: 'settings', - ready: busy || Promise.resolve(true), - /** @type {PrefsValues} */ - defaults: new Proxy({}, { - get: (_, key) => deepCopy(defaults[key]), - }), - knownKeys: Object.keys(defaults), - /** @type {PrefsValues} */ - get values() { - return deepCopy(values); - }, - __defaults: defaults, // direct reference, be careful! - __values: values, // direct reference, be careful! + 'popupWidth': 246, // popup width in pixels + 'popupWidthMax': 280, // popup width in pixels - get(key) { - const {[key]: res = warnUnknown(key)} = values; - return res && typeof res === 'object' ? deepCopy(res) : res; - }, + 'updateInterval': 24, // user-style automatic update interval, hours (0 = disable) + 'updateOnlyEnabled': false, +}; +const warnUnknown = console.warn.bind(console, 'Unknown preference "%s"'); +/** @type {PrefsValues} */ +const values = self.prefs = deepCopy(defaults); +const onChange = {}; +const isBg = __ENTRY === 'background'; +// A scoped listener won't trigger for our [big] stuff in `local`, Chrome 73+, FF +const onSync = chrome.storage.sync.onChanged; - set(key, val, isSynced) { - const old = values[key]; - const def = defaults[key]; - const type = typeof def; - if (!type) return warnUnknown(key); - if (type !== typeof val) { - val = type === 'string' ? `${val}` : - type === 'number' ? +val || 0 : - type === 'boolean' ? val === 'true' || val !== 'false' && !!val : - null; - } - if (val === old || type === 'object' && deepEqual(val, old)) return; - values[key] = val; - const fns = onChange[key]; - if (fns) for (const fn of fns) fn(key, val); - if (!isSynced && !isBg) API.prefs.set(key, val); - /* browser.storage is slow and can randomly lose values if the tab was closed immediately, - so we're sending the value to the background script which will save it to the storage; - the extra bonus is that invokeAPI is immediate in extension tabs. */ - return true; - }, +export const STORAGE_KEY = 'settings'; +/** @type {PrefsValues} */ +const defaultsClone = new Proxy({}, { + get: (_, key) => deepCopy(defaults[key]), +}); +export const knownKeys = Object.keys(defaults); - reset(key) { - prefs.set(key, deepCopy(defaults[key])); - }, +export const get = key => { + const {[key]: res = warnUnknown(key)} = values; + return res && typeof res === 'object' ? deepCopy(res) : res; +}; - /** - * @param {?string|string[]} keys - pref ids or a falsy value to subscribe to everything - * @param {function(key:string?, value:any?)} fn - * @param {boolean} [runNow] - when truthy, the listener is called immediately: - * 1) if `keys` is an array of keys, each `key` will be fired separately with a real `value` - * 2) if `keys` is falsy, no key/value will be provided - */ - subscribe(keys, fn, runNow) { - if (!fn) return; - let toRun; - for (const key of Array.isArray(keys) ? new Set(keys) : [keys]) { - if (!(key in defaults)) { warnUnknown(key); continue; } - (onChange[key] || (onChange[key] = new Set())).add(fn); - if (runNow) { - if (!busy) fn(key, values[key]); - else (toRun || (toRun = [])).push(key); - } - } - if (toRun) return busy.then(() => toRun.forEach(key => fn(key, values[key]))); - }, +export const set = (key, val, isSynced) => { + const old = values[key]; + const def = defaults[key]; + const type = typeof def; + if (!type) return warnUnknown(key); + if (type !== typeof val) { + val = type === 'string' ? `${val}` : + type === 'number' ? +val || 0 : + type === 'boolean' ? val === 'true' || val !== 'false' && !!val : + null; + } + if (val === old || type === 'object' && deepEqual(val, old)) return; + values[key] = val; + const fns = onChange[key]; + if (fns) for (const fn of fns) fn(key, val); + if (!isSynced && !isBg) API.prefs.set(key, val); + /* browser.storage is slow and can randomly lose values if the tab was closed immediately, + so we're sending the value to the background script which will save it to the storage; + the extra bonus is that invokeAPI is immediate in extension tabs. */ + return true; +}; - unsubscribe(keys, fn) { - for (const key of Array.isArray(keys) ? keys : [keys]) { - const fns = onChange[key]; - if (fns) { - fns.delete(fn); - if (!fns.size) delete onChange[key]; - } - } - }, - }; +export const reset = key => { + set(key, deepCopy(defaults[key])); +}; - function setAll(data, fromStorage) { - busy = false; - if (!fromStorage) { - Object.assign(values, data); - return true; +/** + * @param {?string|string[]} keys - pref ids or a falsy value to subscribe to everything + * @param {function(key:string?, value:any?)} fn + * @param {boolean} [runNow] - when truthy, the listener is called immediately: + * 1) if `keys` is an array of keys, each `key` will be fired separately with a real `value` + * 2) if `keys` is falsy, no key/value will be provided + */ +export const subscribe = (keys, fn, runNow) => { + if (!fn) return; + let toRun; + for (const key of Array.isArray(keys) ? new Set(keys) : [keys]) { + if (!(key in defaults)) { warnUnknown(key); continue; } + (onChange[key] || (onChange[key] = new Set())).add(fn); + if (runNow) { + if (!busy) fn(key, values[key]); + else (toRun || (toRun = [])).push(key); } - // checking default values that were deleted from current storage - for (const key in fromStorage) { - if (!(key in data) && key in defaults) prefs.set(key, defaults[key], true); - } - // setting current value + deleting from the source if it's unchanged (for bg-prefs.js) - for (const key in data || (data = {})) { - if (!prefs.set(key, data[key], true)) if (isBg) delete data[key]; + } + if (toRun) return busy.then(() => toRun.forEach(key => fn(key, values[key]))); +}; + +export const unsubscribe = (keys, fn) => { + for (const key of Array.isArray(keys) ? keys : [keys]) { + const fns = onChange[key]; + if (fns) { + fns.delete(fn); + if (!fns.size) delete onChange[key]; } - return !isBg || data; } -})(); +}; + +function setAll(data, fromStorage) { + busy = false; + if (!fromStorage) { + Object.assign(values, data); + return true; + } + // checking default values that were deleted from current storage + for (const key in fromStorage) { + if (!(key in data) && key in defaults) set(key, defaults[key], true); + } + // setting current value + deleting from the source if it's unchanged (for bg-prefs.js) + for (const key in data || (data = {})) { + if (!set(key, data[key], true)) if (isBg) delete data[key]; + } + return !isBg || data; +} + +if (isBg) { + busy = new Promise(cb => (setReady = cb)); + busy.set = (...args) => setReady(setAll(...args)); +} else if (window === parent) { + busy = API.prefs.get().then(setAll); +} else { + setAll(deepCopy(parent.prefs)); // using deepCopy of this realm +} + +(onSync || chrome.storage.onChanged).addListener((changes, area) => { + if (busy) return; + // eslint-disable-next-line no-use-before-define + const data = (onSync || area === 'sync') && changes[STORAGE_KEY]; + if (data) setAll(data.newValue, data.oldValue); +}); + +export const ready = busy || Promise.resolve(true); +export { + defaultsClone as defaults, + defaults as __defaults, // direct reference, be careful! + values as __values, // direct reference, be careful! +}; diff --git a/src/js/router.js b/src/js/router.js index a287f4ae4db..09eee4b218a 100644 --- a/src/js/router.js +++ b/src/js/router.js @@ -1,8 +1,8 @@ -/* global $ */// dom.js -/* global deepEqual */// toolbox.js -/* global msg */ -'use strict'; +import {$} from '/js/dom'; +import * as msg from '/js/msg'; +import {deepEqual} from '/js/toolbox'; +// TODO: export directly const router = { buffer: (history.state || {}).buffer || [], watchers: [], @@ -116,3 +116,5 @@ msg.on(e => { return true; } }); + +export default router; diff --git a/src/js/sections-util.js b/src/js/sections-util.js index 0f468af08e6..144ccc2f42e 100644 --- a/src/js/sections-util.js +++ b/src/js/sections-util.js @@ -1,14 +1,5 @@ -'use strict'; - -/* exported - calcStyleDigest - MozDocMapper - styleCodeEmpty - styleJSONseemsValid - styleSectionsEqual -*/ - -const MozDocMapper = { +// TODO: export directly +export const MozDocMapper = { TO_CSS: { urls: 'url', urlPrefixes: 'url-prefix', @@ -66,19 +57,20 @@ const MozDocMapper = { }, }; +const STYLE_CODE_EMPTY_RE = /\s+|\/\*([^*]+|\*(?!\/))*(\*\/|$)|@namespace[^;]+;|@charset[^;]+;/giyu; + /** @param {StyleSection} sec */ -function styleCodeEmpty(sec) { +export function styleCodeEmpty(sec) { const {code} = sec; let res = !code; if (res || (res = sec._empty) != null) return res; const len = code.length; - const {rx} = styleCodeEmpty; rx.lastIndex = 0; + const rx = STYLE_CODE_EMPTY_RE; rx.lastIndex = 0; let i = 0; while (rx.exec(code) && (i = rx.lastIndex) !== len) {/**/} Object.defineProperty(sec, '_empty', {value: res = i === len, configurable: true}); styleCodeEmpty.lastIndex = i; return res; } -styleCodeEmpty.rx = /\s+|\/\*([^*]+|\*(?!\/))*(\*\/|$)|@namespace[^;]+;|@charset[^;]+;/giyu; /** * The sections are checked in successive order because it matters when many sections @@ -87,7 +79,7 @@ styleCodeEmpty.rx = /\s+|\/\*([^*]+|\*(?!\/))*(\*\/|$)|@namespace[^;]+;|@charset * @param {Object} b - second style object * @returns {?boolean} */ -function styleSectionsEqual({sections: a}, {sections: b}) { +export function styleSectionsEqual({sections: a}, {sections: b}) { const targets = ['urls', 'urlPrefixes', 'domains', 'regexps']; return a && b && a.length === b.length && a.every(sameSection); function sameSection(secA, i) { @@ -108,7 +100,7 @@ function styleSectionsEqual({sections: a}, {sections: b}) { } } -async function calcStyleDigest(style) { +export async function calcStyleDigest(style) { // retain known properties in an arbitrarily predefined order const src = style.usercssData ? style.sourceCode @@ -125,7 +117,7 @@ async function calcStyleDigest(style) { return Array.from(new Uint8Array(res), b => (0x100 + b).toString(16).slice(1)).join(''); } -function styleJSONseemsValid(json) { +export function styleJSONseemsValid(json) { return json && typeof json.name == 'string' && json.name.trim() diff --git a/src/js/storage-util.js b/src/js/storage-util.js index 7daa4b7aaf1..7cadb353f1f 100644 --- a/src/js/storage-util.js +++ b/src/js/storage-util.js @@ -1,52 +1,36 @@ -/* global tryJSONparse */// toolbox.js -'use strict'; +import browser from '/js/browser'; +import {tryJSONparse} from './toolbox'; +import {compressToUTF16, decompressFromUTF16} from 'lz-string-unsafe'; -(() => { - let LZString; +const StorageExtras = { + async getValue(key) { + return (await this.get(key))[key]; + }, + async setValue(key, value) { + await this.set({[key]: value}); + }, + async getLZValue(key) { + return (await this.getLZValues([key]))[key]; + }, + async getLZValues(keys = Object.values(this.LZ_KEY)) { + const data = await this.get(keys); + for (const key of keys) { + const value = data[key]; + data[key] = value && tryJSONparse(decompressFromUTF16(value)); + } + return data; + }, + setLZValue(key, value) { + return this.setValue(key, compressToUTF16(JSON.stringify(value))); + }, +}; - /** @namespace StorageExtras */ - const StorageExtras = { - async getValue(key) { - return (await this.get(key))[key]; - }, - async setValue(key, value) { - await this.set({[key]: value}); - }, - async getLZValue(key) { - return (await this.getLZValues([key]))[key]; - }, - async getLZValues(keys = Object.values(this.LZ_KEY)) { - const [data] = await Promise.all([ - this.get(keys), - LZString || loadLZString(), - ]); - for (const key of keys) { - const value = data[key]; - data[key] = value && tryJSONparse(LZString.decompressFromUTF16(value)); - } - return data; - }, - async setLZValue(key, value) { - if (!LZString) await loadLZString(); - return this.setValue(key, LZString.compressToUTF16(JSON.stringify(value))); - }, - }; - /** @namespace StorageExtrasSync */ - const StorageExtrasSync = { - LZ_KEY: { - csslint: 'editorCSSLintConfig', - stylelint: 'editorStylelintConfig', - usercssTemplate: 'usercssTemplate', - }, - }; - - async function loadLZString() { - await require(['/vendor/lz-string-unsafe/lz-string-unsafe.min']); - LZString = window.LZString || window.LZStringUnsafe; - } - - /** @type {chrome.storage.StorageArea|StorageExtras} */ - window.chromeLocal = Object.assign(browser.storage.local, StorageExtras); - /** @type {chrome.storage.StorageArea|StorageExtras|StorageExtrasSync} */ - window.chromeSync = Object.assign(browser.storage.sync, StorageExtras, StorageExtrasSync); -})(); +export const chromeLocal = Object.assign(browser.storage.local, StorageExtras); +export const chromeSync = Object.assign(browser.storage.sync, StorageExtras, { + // TODO: export directly + LZ_KEY: { + csslint: 'editorCSSLintConfig', + stylelint: 'editorStylelintConfig', + usercssTemplate: 'usercssTemplate', + }, +}); diff --git a/src/js/themer.js b/src/js/themer.js index bb5b4a7dbf9..46ca9702648 100644 --- a/src/js/themer.js +++ b/src/js/themer.js @@ -1,8 +1,3 @@ -/* global $ $create */// dom.js -/* global API msg */// msg.js -/* global FIREFOX */// toolbox.js -'use strict'; - /** * This file must be loaded in a + diff --git a/src/background/content-scripts.js b/src/background/content-scripts.js index 61dd8b1fe49..6ed03091f8e 100644 --- a/src/background/content-scripts.js +++ b/src/background/content-scripts.js @@ -1,6 +1,6 @@ import browser from '/js/browser'; import {sendTab} from '/js/msg'; -import {ignoreChromeError, stringAsRegExpStr, URLS} from '/js/toolbox'; +import {CHROME, ignoreChromeError, stringAsRegExpStr, URLS} from '/js/toolbox'; import {bgReady} from './common'; import tabMan from './tab-manager'; diff --git a/src/background/icon-manager.js b/src/background/icon-manager.js index 4fad968a907..2680dd8560d 100644 --- a/src/background/icon-manager.js +++ b/src/background/icon-manager.js @@ -1,5 +1,5 @@ import * as prefs from '/js/prefs'; -import {debounce, FIREFOX, ignoreChromeError, UA} from '/js/toolbox'; +import {CHROME, debounce, FIREFOX, ignoreChromeError, UA} from '/js/toolbox'; import * as colorScheme from './color-scheme'; import {addAPI, API, bgReady} from './common'; import tabMan from './tab-manager'; diff --git a/src/background/style-manager.js b/src/background/style-manager.js index 1305a3ab43d..f7d1e90c5ad 100644 --- a/src/background/style-manager.js +++ b/src/background/style-manager.js @@ -1,7 +1,8 @@ import * as prefs from '/js/prefs'; import {calcStyleDigest, styleCodeEmpty} from '/js/sections-util'; import { - deepEqual, isEmptyObj, mapObj, stringAsRegExpStr, tryRegExp, tryURL, UCD, URLS, + CHROME, + deepEqual, FIREFOX, isEmptyObj, mapObj, stringAsRegExpStr, tryRegExp, tryURL, UCD, URLS, } from '/js/toolbox'; import {broadcast, broadcastExtension} from './broadcast'; import broadcastInjectorConfig from './broadcast-injector-config'; diff --git a/src/background/style-via-api.js b/src/background/style-via-api.js index 1a8325754db..d528bb0fb07 100644 --- a/src/background/style-via-api.js +++ b/src/background/style-via-api.js @@ -1,6 +1,6 @@ import browser from '/js/browser'; import * as prefs from '/js/prefs'; -import {isEmptyObj} from '/js/toolbox'; +import {FIREFOX, isEmptyObj} from '/js/toolbox'; import {addAPI, API} from './common'; import {getSectionsByUrl, order} from './style-manager'; diff --git a/src/background/style-via-webrequest.js b/src/background/style-via-webrequest.js index 6ae1ec336d3..fbe25e47af2 100644 --- a/src/background/style-via-webrequest.js +++ b/src/background/style-via-webrequest.js @@ -1,7 +1,7 @@ import popupGetStyles from '/js/popup-get-styles'; import * as prefs from '/js/prefs'; -import {ignoreChromeError, URLS} from '/js/toolbox'; -import {API, bgReady} from './common'; +import {CHROME, FIREFOX, ignoreChromeError, URLS} from '/js/toolbox'; +import {API} from './common'; import {getSectionsByUrl} from './style-manager'; import tabMan from './tab-manager'; diff --git a/src/background/tab-util.js b/src/background/tab-util.js index 0d424369744..e437c7d1792 100644 --- a/src/background/tab-util.js +++ b/src/background/tab-util.js @@ -1,6 +1,6 @@ import browser from '/js/browser'; import * as msg from '/js/msg'; -import {getActiveTab} from '/js/toolbox'; +import {CHROME, FIREFOX, getActiveTab} from '/js/toolbox'; import {addAPI, API} from './common'; import * as prefs from '/js/prefs'; diff --git a/src/background/token-manager.js b/src/background/token-manager.js index 64bbd766128..d8443a393dd 100644 --- a/src/background/token-manager.js +++ b/src/background/token-manager.js @@ -1,5 +1,5 @@ import browser from '/js/browser'; -import {clamp, URLS} from '/js/toolbox'; +import {clamp, FIREFOX, URLS} from '/js/toolbox'; import {chromeLocal} from '/js/storage-util'; import {detectVivaldi, isVivaldi} from './common'; import {waitForTabUrl} from './tab-util'; diff --git a/src/content/style-injector.js b/src/content/style-injector.js index fdd2d89c23b..f1b3cc7dd7b 100644 --- a/src/content/style-injector.js +++ b/src/content/style-injector.js @@ -306,7 +306,8 @@ export default ({ } if (retry && ffCsp && (ass = wrappedDoc[kAss])) { // ffCsp bug got fixed initAss(); - console.debug('Stylus switched to document.adoptedStyleSheets due to a strict CSP of the page'); + console.debug( + 'Stylus switched to document.adoptedStyleSheets due to a strict CSP of the page'); return createStyle(style); } creationDoc = document; @@ -355,7 +356,7 @@ export default ({ } if (!bad) return; if (!mutations || ++reorderCnt < 10) addAllElements(); - else console.debug(`Stylus ignored wrong order of styles to avoid an infinite loop of mutations.`); + else console.debug(`Stylus ignored wrong order of styles to avoid an infinite loop of mutations.`); // eslint-disable-line max-len const t = performance.now(); if (t - reorderStart > 250) { reorderCnt = 0; diff --git a/src/edit.html b/src/edit.html index 8df76429c89..093bf973f4e 100644 --- a/src/edit.html +++ b/src/edit.html @@ -5,8 +5,8 @@ - - + +