From 570503b7f12df7d12af29905da97131b032c7da0 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 14 Nov 2022 15:02:44 +0100 Subject: Require PHP 7.2+ (#4848) Drop PHP 7.0- as planned https://github.com/FreshRSS/FreshRSS/discussions/3321#discussioncomment-835704 --- docs/en/admins/02_Prerequisites.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/en') diff --git a/docs/en/admins/02_Prerequisites.md b/docs/en/admins/02_Prerequisites.md index 41dabc651..c2a2b3fa7 100644 --- a/docs/en/admins/02_Prerequisites.md +++ b/docs/en/admins/02_Prerequisites.md @@ -7,7 +7,7 @@ You need to verify that your server can run FreshRSS before installing it. If yo | Software | Recommended | Also Works With | | ------------- | ----------------------- | ----------------------- | | Web server | **Apache 2** | Nginx, lighttpd | -| PHP | **PHP 7+** | | +| PHP | **PHP 7.2+** | | | PHP modules | Required: libxml, cURL, JSON, PDO_MySQL, PCRE and ctype.
Required (32-bit only): GMP
Recommended: Zlib, mbstring, iconv, ZipArchive
*For the whole modules list see [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L7-L9)* | | | Database | **MySQL 5.5.3+** | SQLite 3.7.4+, PostgreSQL 9.5+ | | Browser | **Firefox** | Chrome, Opera, Safari, or Edge | -- cgit v1.2.3 From 3fb8ab8eb5c88042320bbe006825b21f5a8f21de Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 9 Jan 2023 12:59:09 +0100 Subject: Handling of parentheses as special characters in searches (#4989) #fix https://github.com/FreshRSS/FreshRSS/issues/4987 --- app/Models/BooleanSearch.php | 8 +++++--- docs/en/users/03_Main_view.md | 2 ++ docs/fr/users/03_Main_view.md | 2 ++ tests/app/Models/SearchTest.php | 5 +++++ 4 files changed, 14 insertions(+), 3 deletions(-) (limited to 'docs/en') diff --git a/app/Models/BooleanSearch.php b/app/Models/BooleanSearch.php index b1c7bbd3b..279040a5a 100644 --- a/app/Models/BooleanSearch.php +++ b/app/Models/BooleanSearch.php @@ -118,8 +118,9 @@ class FreshRSS_BooleanSearch { $nextOperator = 'AND'; while ($i < $length) { $c = $input[$i]; + $backslashed = $i >= 1 ? $input[$i - 1] === '\\' : false; - if ($c === '(') { + if ($c === '(' && !$backslashed) { $hasParenthesis = true; $before = trim($before); @@ -164,11 +165,12 @@ class FreshRSS_BooleanSearch { $i++; while ($i < $length) { $c = $input[$i]; - if ($c === '(') { + $backslashed = $input[$i - 1] === '\\'; + if ($c === '(' && !$backslashed) { // One nested level deeper $parentheses++; $sub .= $c; - } elseif ($c === ')') { + } elseif ($c === ')' && !$backslashed) { $parentheses--; if ($parentheses === 0) { // Found the matching closing parenthesis diff --git a/docs/en/users/03_Main_view.md b/docs/en/users/03_Main_view.md index eb8fe0f01..d940774f5 100644 --- a/docs/en/users/03_Main_view.md +++ b/docs/en/users/03_Main_view.md @@ -247,6 +247,8 @@ Finally, parentheses may be used to express more complex queries, with basic neg * `(author:Alice intitle:hello) !(author:Bob intitle:world)` * `!(S:1 OR S:2)` +> ℹ️ If you need to search for a parenthesis, it needs to be escaped like `\(` or `\)` + ### By sorting by date You can change the sort order by clicking the toggle button available in the header. diff --git a/docs/fr/users/03_Main_view.md b/docs/fr/users/03_Main_view.md index 3a65c1f7f..3ca3b907c 100644 --- a/docs/fr/users/03_Main_view.md +++ b/docs/fr/users/03_Main_view.md @@ -275,3 +275,5 @@ Enfin, les parenthèses peuvent être utilisées pour des expressions plus compl * `!((author:Alice intitle:bonjour) OR (author:Bob intitle:monde))` * `(author:Alice intitle:bonjour) !(author:Bob intitle:monde)` * `!(S:1 OR S:2)` + +> ℹ️ Si vous devez chercher une parenthèse, elle doit être *échappée* comme suit : `\(` ou `\)` diff --git a/tests/app/Models/SearchTest.php b/tests/app/Models/SearchTest.php index fe686e7ba..52c10244d 100644 --- a/tests/app/Models/SearchTest.php +++ b/tests/app/Models/SearchTest.php @@ -339,6 +339,11 @@ class SearchTest extends PHPUnit\Framework\TestCase { '(author:Alice intitle:hello) !(author:Bob intitle:world)', ' ((e.author LIKE ? AND e.title LIKE ? )) AND NOT ((e.author LIKE ? AND e.title LIKE ? )) ', ['%Alice%', '%hello%', '%Bob%', '%world%'], + ], + [ + 'intitle:"\\(test\\)"', + '(e.title LIKE ? )', + ['%\\(test\\)%'], ] ]; } -- cgit v1.2.3 From 1d9d4e3e3c8dd020ab4d333436264eaa3ef201cd Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 9 Jan 2023 12:59:30 +0100 Subject: Update dev dependencies (#4993) Related to https://github.com/FreshRSS/FreshRSS/pull/4991 Required a few changes in code to pass the tests --- .github/workflows/tests.yml | 10 +- .typos.toml | 3 +- Makefile | 44 +- app/Controllers/updateController.php | 6 +- app/Models/Entry.php | 2 +- app/Models/Searchable.php | 4 + app/Models/UserQuery.php | 27 +- composer.json | 2 +- composer.lock | 62 +- docs/en/admins/05_Configuring_email_validation.md | 2 +- docs/en/developers/02_Github.md | 2 +- docs/en/internationalization.md | 2 +- lib/http-conditional.php | 2 +- p/ext.php | 1 - package-lock.json | 1509 ++++++++++++--------- package.json | 17 +- tests/app/Models/UserQueryTest.php | 12 +- 17 files changed, 955 insertions(+), 752 deletions(-) (limited to 'docs/en') diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5751f685b..6e1e6b0a6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -55,7 +55,7 @@ jobs: uses: actions/setup-node@v3 with: # https://nodejs.org/en/about/releases/ - node-version: '16' + node-version: '18' cache: 'npm' - run: npm ci @@ -79,14 +79,14 @@ jobs: uses: actions/cache@v3 with: path: bin - key: ${{ runner.os }}-bin-shfmt@v3.5.1-hadolint@v2.10.0-typos@v1.10.1 + key: ${{ runner.os }}-bin-shfmt@v3.6.0-hadolint@v2.12.0-typos@v1.13.6 - name: Add ./bin/ to $PATH run: mkdir -p bin/ && echo "${PWD}/bin" >> $GITHUB_PATH - name: Install shfmt if: steps.shell-cache.outputs.cache-hit != 'true' - run: GOBIN=${PWD}/bin/ go install mvdan.cc/sh/v3/cmd/shfmt@v3.5.1 + run: GOBIN=${PWD}/bin/ go install mvdan.cc/sh/v3/cmd/shfmt@v3.6.0 - name: Check shell script syntax # shellcheck is pre-installed https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2204-Readme.md @@ -94,7 +94,7 @@ jobs: - name: Install hadolint if: steps.shell-cache.outputs.cache-hit != 'true' - run: curl -sL -o ./bin/hadolint "https://github.com/hadolint/hadolint/releases/download/v2.10.0/hadolint-$(uname -s)-$(uname -m)" && chmod 700 ./bin/hadolint + run: curl -sL -o ./bin/hadolint "https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-$(uname -s)-$(uname -m)" && chmod 700 ./bin/hadolint - name: Check Dockerfile syntax run: find . -name 'Dockerfile*' -print0 | xargs -0 -n1 ./bin/hadolint --failure-threshold warning @@ -103,7 +103,7 @@ jobs: if: steps.shell-cache.outputs.cache-hit != 'true' run: | cd bin ; - wget -q 'https://github.com/crate-ci/typos/releases/download/v1.10.1/typos-v1.10.1-x86_64-unknown-linux-musl.tar.gz' && + wget -q 'https://github.com/crate-ci/typos/releases/download/v1.13.6/typos-v1.13.6-x86_64-unknown-linux-musl.tar.gz' && tar -xvf *.tar.gz './typos' && chmod +x typos && rm *.tar.gz ; diff --git a/.typos.toml b/.typos.toml index f4b7d5f5a..38a2a1cee 100644 --- a/.typos.toml +++ b/.typos.toml @@ -3,7 +3,7 @@ ot = "ot" Ths2 = "Ths2" [default.extend-words] -ba = "ba" +referer = "referer" [files] extend-exclude = [ @@ -33,6 +33,7 @@ extend-exclude = [ "app/i18n/zh-cn/", "bin/", "CHANGELOG-old.md", + "composer.lock", "data/", "docs/fr/", "lib/phpgt/", diff --git a/Makefile b/Makefile index 6216dfcec..d94fd704a 100644 --- a/Makefile +++ b/Makefile @@ -60,40 +60,37 @@ stop: ## Stop FreshRSS container if any ## Tests and linter ## ###################### .PHONY: test -test: bin/phpunit ## Run the test suite - $(PHP) ./bin/phpunit --bootstrap ./tests/bootstrap.php ./tests +test: vendor/bin/phpunit ## Run the test suite + $(PHP) vendor/bin/phpunit --bootstrap ./tests/bootstrap.php ./tests .PHONY: lint -lint: bin/phpcs ## Run the linter on the PHP files - $(PHP) ./bin/phpcs . -p -s +lint: vendor/bin/phpcs ## Run the linter on the PHP files + $(PHP) vendor/bin/phpcs . -p -s .PHONY: lint-fix -lint-fix: bin/phpcbf ## Fix the errors detected by the linter - $(PHP) ./bin/phpcbf . -p -s +lint-fix: vendor/bin/phpcbf ## Fix the errors detected by the linter + $(PHP) vendor/bin/phpcbf . -p -s bin/composer: mkdir -p bin/ - wget 'https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer' -O - -q | php -- --quiet --install-dir='./bin/' --filename='composer' + wget 'https://raw.githubusercontent.com/composer/getcomposer.org/b5dbe5ebdec95ce71b3128b359bd5a85cb0a722d/web/installer' -O - -q | php -- --quiet --install-dir='./bin/' --filename='composer' -bin/phpunit: - mkdir -p bin/ - wget -O bin/phpunit 'https://phar.phpunit.de/phpunit-9.5.20.phar' - echo '6becad2da5c37f5ad101cc665ef05a2f1a6a45d2427c8edcc74f72c92fb1e05a bin/phpunit' | sha256sum -c - || rm bin/phpunit +vendor/bin/phpunit: bin/composer + bin/composer install --prefer-dist --no-progress + ln -s ../vendor/bin/phpunit bin/phpunit -bin/phpcs: - mkdir -p bin/ - wget -O bin/phpcs 'https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.7.1/phpcs.phar' - echo '7a14323a14af9f58302d15442492ee1076a8cd72c018a816cb44965bf3a9b015 bin/phpcs' | sha256sum -c - || rm bin/phpcs +vendor/bin/phpcs: bin/composer + bin/composer install --prefer-dist --no-progress + ln -s ../vendor/bin/phpcs bin/phpcs -bin/phpcbf: - mkdir -p bin/ - wget -O bin/phpcbf 'https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.7.1/phpcbf.phar' - echo 'c93c0e83cbda21c21f849ccf0f4b42979d20004a5a6172ed0ea270eca7ae6fa8 bin/phpcbf' | sha256sum -c - || rm bin/phpcbf +vendor/bin/phpcbf: bin/composer + bin/composer install --prefer-dist --no-progress + ln -s ../vendor/bin/phpcbf bin/phpcbf bin/typos: mkdir -p bin/ cd bin ; \ - wget -q 'https://github.com/crate-ci/typos/releases/download/v1.10.1/typos-v1.10.1-x86_64-unknown-linux-musl.tar.gz' && \ + wget -q 'https://github.com/crate-ci/typos/releases/download/v1.13.6/typos-v1.13.6-x86_64-unknown-linux-musl.tar.gz' && \ tar -xvf *.tar.gz './typos' && \ chmod +x typos && \ rm *.tar.gz ; \ @@ -102,6 +99,9 @@ bin/typos: node_modules/.bin/eslint: npm install +node_modules/.bin/rtlcss: + npm install + vendor/bin/phpstan: bin/composer bin/composer install --prefer-dist --no-progress @@ -181,8 +181,8 @@ endif ## TOOLS ## ########### .PHONY: rtl -rtl: ## Generate RTL CSS files - rtlcss -d p/themes/ && find p/themes/ -type f -name '*.rtl.rtl.css' -delete +rtl: node_modules/.bin/rtlcss ## Generate RTL CSS files + npm run-script rtlcss .PHONY: pot pot: ## Generate POT templates for docs diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index ae7d613a7..f638ce96c 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -23,7 +23,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController { if ($return != 0) { throw new Exception($errorMessage); } - $line = is_array($output) ? implode('', $output) : $output; + $line = implode('', $output); if ($line !== 'master' && $line !== 'dev') { return true; // not on master or dev, nothing to do } @@ -54,14 +54,14 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController { $output = []; exec('git status -sb --porcelain remote', $output, $return); } else { - $line = is_array($output) ? implode('; ', $output) : $output; + $line = implode('; ', $output); Minz_Log::warning('git fetch warning: ' . $line); } } catch (Exception $e) { Minz_Log::warning('git fetch error: ' . $e->getMessage()); } chdir($cwd); - $line = is_array($output) ? implode('; ', $output) : $output; + $line = implode('; ', $output); return $line == '' || strpos($line, '[behind') !== false || strpos($line, '[ahead') !== false || strpos($line, '[gone') !== false; } diff --git a/app/Models/Entry.php b/app/Models/Entry.php index ec7629253..16de8beb6 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -76,7 +76,7 @@ class FreshRSS_Entry extends Minz_Model { $dao['guid'] ?? '', $dao['title'] ?? '', $dao['author'] ?? '', - $dao['content'] ?? '', + $dao['content'], $dao['link'] ?? '', $dao['date'] ?? 0, $dao['is_read'] ?? false, diff --git a/app/Models/Searchable.php b/app/Models/Searchable.php index d5bcea49d..a15a44ed7 100644 --- a/app/Models/Searchable.php +++ b/app/Models/Searchable.php @@ -2,5 +2,9 @@ interface FreshRSS_Searchable { + /** + * @param int|string $id + * @return Minz_Model + */ public function searchById($id); } diff --git a/app/Models/UserQuery.php b/app/Models/UserQuery.php index 964324bf7..4c7e2a8f7 100644 --- a/app/Models/UserQuery.php +++ b/app/Models/UserQuery.php @@ -18,16 +18,17 @@ class FreshRSS_UserQuery { private $search; private $state; private $url; + /** @var FreshRSS_FeedDAO */ private $feed_dao; + /** @var FreshRSS_CategoryDAO */ private $category_dao; + /** @var FreshRSS_TagDAO */ private $tag_dao; /** * @param array $query - * @param FreshRSS_Searchable $feed_dao - * @param FreshRSS_Searchable $category_dao */ - public function __construct($query, FreshRSS_Searchable $feed_dao = null, FreshRSS_Searchable $category_dao = null, FreshRSS_Searchable $tag_dao = null) { + public function __construct($query, FreshRSS_FeedDAO $feed_dao = null, FreshRSS_CategoryDAO $category_dao = null, FreshRSS_TagDAO $tag_dao = null) { $this->category_dao = $category_dao; $this->feed_dao = $feed_dao; $this->tag_dao = $tag_dao; @@ -83,21 +84,22 @@ class FreshRSS_UserQuery { private function parseGet($get) { $this->get = $get; if (preg_match('/(?P[acfst])(_(?P\d+))?/', $get, $matches)) { + $id = intval($matches['id'] ?? '0'); switch ($matches['type']) { case 'a': $this->parseAll(); break; case 'c': - $this->parseCategory($matches['id']); + $this->parseCategory($id); break; case 'f': - $this->parseFeed($matches['id']); + $this->parseFeed($id); break; case 's': $this->parseFavorite(); break; case 't': - $this->parseTag($matches['id']); + $this->parseTag($id); break; } } @@ -114,11 +116,10 @@ class FreshRSS_UserQuery { /** * Parse the query string when it is a "category" query * - * @param integer $id * @throws FreshRSS_DAO_Exception */ - private function parseCategory($id) { - if (is_null($this->category_dao)) { + private function parseCategory(int $id) { + if ($this->category_dao === null) { throw new FreshRSS_DAO_Exception('Category DAO is not loaded in UserQuery'); } $category = $this->category_dao->searchById($id); @@ -133,11 +134,10 @@ class FreshRSS_UserQuery { /** * Parse the query string when it is a "feed" query * - * @param integer $id * @throws FreshRSS_DAO_Exception */ - private function parseFeed($id) { - if (is_null($this->feed_dao)) { + private function parseFeed(int $id) { + if ($this->feed_dao === null) { throw new FreshRSS_DAO_Exception('Feed DAO is not loaded in UserQuery'); } $feed = $this->feed_dao->searchById($id); @@ -152,10 +152,9 @@ class FreshRSS_UserQuery { /** * Parse the query string when it is a "tag" query * - * @param integer $id * @throws FreshRSS_DAO_Exception */ - private function parseTag($id) { + private function parseTag(int $id) { if ($this->tag_dao == null) { throw new FreshRSS_DAO_Exception('Tag DAO is not loaded in UserQuery'); } diff --git a/composer.json b/composer.json index bac516c34..d6cac9e9c 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "ext-phar": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "phpstan/phpstan": "~1.7.14", + "phpstan/phpstan": "~1.9.7", "phpunit/phpunit": "^9", "squizlabs/php_codesniffer": "^3.7" }, diff --git a/composer.lock b/composer.lock index 696088da1..a2234ddba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,35 +4,35 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a177c11dee892e1293efc7331465081b", + "content-hash": "d8f96ca83672be5007207d38e14e1c29", "packages": [], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9", + "doctrine/coding-standard": "^9 || ^11", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^0.16 || ^1", "phpstan/phpstan": "^1.4", "phpstan/phpstan-phpunit": "^1", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "vimeo/psalm": "^4.30 || ^5.4" }, "type": "library", "autoload": { @@ -59,7 +59,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" }, "funding": [ { @@ -75,7 +75,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:15:36+00:00" }, { "name": "myclabs/deep-copy", @@ -305,16 +305,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.7.15", + "version": "1.9.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cd0202ea1b1fc6d1bbe156c6e2e18a03e0ff160a" + "reference": "0501435cd342eac7664bd62155b1ef907fc60b6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd0202ea1b1fc6d1bbe156c6e2e18a03e0ff160a", - "reference": "cd0202ea1b1fc6d1bbe156c6e2e18a03e0ff160a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0501435cd342eac7664bd62155b1ef907fc60b6f", + "reference": "0501435cd342eac7664bd62155b1ef907fc60b6f", "shasum": "" }, "require": { @@ -338,9 +338,13 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.7.15" + "source": "https://github.com/phpstan/phpstan/tree/1.9.7" }, "funding": [ { @@ -351,29 +355,25 @@ "url": "https://github.com/phpstan", "type": "github" }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", "type": "tidelift" } ], - "time": "2022-06-20T08:29:01+00:00" + "time": "2023-01-04T21:59:57+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.18", + "version": "9.2.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a" + "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/12fddc491826940cf9b7e88ad9664cf51f0f6d0a", - "reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", + "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", "shasum": "" }, "require": { @@ -429,7 +429,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.18" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23" }, "funding": [ { @@ -437,7 +437,7 @@ "type": "github" } ], - "time": "2022-10-27T13:35:33+00:00" + "time": "2022-12-28T12:41:10+00:00" }, { "name": "phpunit/php-file-iterator", @@ -682,16 +682,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.26", + "version": "9.5.27", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2" + "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2", - "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38", + "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38", "shasum": "" }, "require": { @@ -764,7 +764,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27" }, "funding": [ { @@ -780,7 +780,7 @@ "type": "tidelift" } ], - "time": "2022-10-28T06:00:21+00:00" + "time": "2022-12-09T07:31:23+00:00" }, { "name": "sebastian/cli-parser", diff --git a/docs/en/admins/05_Configuring_email_validation.md b/docs/en/admins/05_Configuring_email_validation.md index 69a06b53f..aec6b8b75 100644 --- a/docs/en/admins/05_Configuring_email_validation.md +++ b/docs/en/admins/05_Configuring_email_validation.md @@ -68,7 +68,7 @@ Once you’re done, don’t forget to reconfigure your environment to `productio ## Access the validation URL during development -You might find painful to configure a SMTP server when you’re developping and +You might find painful to configure a SMTP server when you’re developing and `mail` function will not work on your local machine. For the moment, there is no easy way to access the validation URL unless forging it. You’ll need to information: diff --git a/docs/en/developers/02_Github.md b/docs/en/developers/02_Github.md index 4e6a84ab3..066d6ffb0 100644 --- a/docs/en/developers/02_Github.md +++ b/docs/en/developers/02_Github.md @@ -53,7 +53,7 @@ Now you can create a PR based on your branch. ## How to write a commit message -A commit message should succintly describe the changes on the first line. For example: +A commit message should succinctly describe the changes on the first line. For example: > Fix broken icon diff --git a/docs/en/internationalization.md b/docs/en/internationalization.md index 3feb4f57c..741a642c7 100644 --- a/docs/en/internationalization.md +++ b/docs/en/internationalization.md @@ -86,7 +86,7 @@ This command adds an IGNORE comment on the translation so the key can be conside ## Add/remove/update a key -If you’re developping a new part of the application, you might want to declare a new translation key. Your first impulse would be to add the key to each file manually: don’t do that, it’s very painful. We provide another command: +If you’re developing a new part of the application, you might want to declare a new translation key. Your first impulse would be to add the key to each file manually: don’t do that, it’s very painful. We provide another command: ```sh make i18n-add-key key=the.key.to.add value='Your string in English' diff --git a/lib/http-conditional.php b/lib/http-conditional.php index 853fdf983..6c7c89d32 100644 --- a/lib/http-conditional.php +++ b/lib/http-conditional.php @@ -7,7 +7,7 @@ - Possibility to control cache for client and proxies (public or private policy, life time). - When $feedMode is set to true, in the case of a RSS/ATOM feed, it puts a timestamp in the global variable $clientCacheDate to allow the sending of only the articles newer than the client's cache. - - When $compression is set to true, compress the data before sending it to the client and persitent connections are allowed. + - When $compression is set to true, compress the data before sending it to the client and persistent connections are allowed. - When $session is set to true, automatically checks if $_SESSION has been modified during the last generation the document. Interface: diff --git a/p/ext.php b/p/ext.php index 2979e2365..9427f8c20 100644 --- a/p/ext.php +++ b/p/ext.php @@ -60,7 +60,6 @@ function is_valid_path_extension($path, $extensionPath, $isStatic = true) { // Static files to serve must be under a `ext_dir/static/` directory. $path_relative_to_ext = substr($path, strlen($real_ext_path) + 1); - // @phpstan-ignore-next-line list(,$static,$file) = sscanf($path_relative_to_ext, '%[^/]/%[^/]/%s'); if (null === $file || 'static' !== $static) { return false; diff --git a/package-lock.json b/package-lock.json index c2c290987..d450ea5fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,47 +7,50 @@ "name": "freshrss", "license": "AGPL-3.0", "devDependencies": { - "eslint": "^8.10.0", + "eslint": "^8.31.0", "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.2.3", - "eslint-plugin-promise": "^6.0.0", + "eslint-plugin-n": "^15.6.0", + "eslint-plugin-promise": "^6.1.1", "markdownlint-cli": "^0.31.1", - "rtlcss": "^3.5.0", - "sass": "^1.52.3", - "stylelint": "^14.9.0", - "stylelint-config-recommended-scss": "^6.0.0", + "rtlcss": "^4.0.0", + "sass": "^1.57.0", + "stylelint": "^14.16.1", + "stylelint-config-recommended-scss": "^8.0.0", "stylelint-order": "^5.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -127,9 +130,9 @@ } }, "node_modules/@csstools/selector-specificity": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz", - "integrity": "sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", "dev": true, "engines": { "node": "^12 || ^14 || >=16" @@ -139,20 +142,20 @@ "url": "https://opencollective.com/csstools" }, "peerDependencies": { - "postcss": "^8.3", + "postcss": "^8.2", "postcss-selector-parser": "^6.0.10" } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", + "espree": "^9.4.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -161,22 +164,38 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -243,9 +262,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -304,9 +323,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -323,15 +342,15 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" }, "engines": { @@ -351,14 +370,14 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -386,6 +405,18 @@ "node": ">=8" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -535,18 +566,6 @@ "node": ">= 6" } }, - "node_modules/clone-regexp": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", - "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==", - "dev": true, - "dependencies": { - "is-regexp": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -566,9 +585,9 @@ "dev": true }, "node_modules/colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "dev": true }, "node_modules/commander": { @@ -587,9 +606,9 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", @@ -664,9 +683,9 @@ } }, "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, "dependencies": { "decamelize": "^1.1.0", @@ -674,6 +693,9 @@ }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decamelize-keys/node_modules/map-obj": { @@ -765,34 +787,43 @@ } }, "node_modules/es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.0.tgz", + "integrity": "sha512-GUGtW7eXQay0c+PRq0sGIKSdaBorfVqsCMhGHo4elP7YVqZu9nCZS4UkK4gv71gOWNMra/PaSKD3ao1oWExO0g==", "dev": true, "dependencies": { "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.0", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.0", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" }, "engines": { "node": ">= 0.4" @@ -801,6 +832,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -827,6 +872,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -840,13 +894,15 @@ } }, "node_modules/eslint": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.18.0.tgz", - "integrity": "sha512-As1EfFMVk7Xc6/CvhssHUjsAQSkpfXvUGMFC3ce8JDe6WvqCgRrLOBQbVpsBFr1X1V+RACOadnzVvcUS5ni2bA==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -856,18 +912,21 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -878,8 +937,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -937,16 +995,20 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "engines": { "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/eslint-module-utils/node_modules/debug": { @@ -958,73 +1020,6 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-module-utils/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-plugin-es": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", @@ -1123,19 +1118,19 @@ "dev": true }, "node_modules/eslint-plugin-n": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.2.3.tgz", - "integrity": "sha512-H+KC7U5R+3IWTeRnACm/4wlqLvS1Q7M6t7BGhn89qXDkZan8HTAEv3ouIONA0ifDwc2YzPFmyPzHuNLddNK4jw==", + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.0.tgz", + "integrity": "sha512-Hd/F7wz4Mj44Jp0H6Jtty13NcE69GNTY0rVlgTIj1XBnGGVI6UTdDrpE6vqu3AHo07bygq/N+7OH/lgz1emUJw==", "dev": true, "dependencies": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", "eslint-utils": "^3.0.0", "ignore": "^5.1.1", - "is-core-module": "^2.9.0", + "is-core-module": "^2.11.0", "minimatch": "^3.1.2", - "resolve": "^1.10.1", - "semver": "^7.3.7" + "resolve": "^1.22.1", + "semver": "^7.3.8" }, "engines": { "node": ">=12.22.0" @@ -1148,9 +1143,9 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", - "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1209,17 +1204,20 @@ } }, "node_modules/espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { - "acorn": "^8.7.1", + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -1264,18 +1262,6 @@ "node": ">=0.10.0" } }, - "node_modules/execall": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", - "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", - "dev": true, - "dependencies": { - "clone-regexp": "^2.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1283,9 +1269,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1323,15 +1309,18 @@ "dev": true }, "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "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==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1391,11 +1380,20 @@ } }, "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1440,12 +1438,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -1456,9 +1448,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "dependencies": { "function-bind": "^1.1.1", @@ -1574,9 +1566,9 @@ } }, "node_modules/globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1588,6 +1580,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -1614,6 +1621,24 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -1665,6 +1690,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -1717,18 +1754,18 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", - "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", + "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==", "dev": true }, "node_modules/import-fresh": { @@ -1791,21 +1828,21 @@ "dev": true }, "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -1813,6 +1850,20 @@ "node": ">= 0.4" } }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1860,9 +1911,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -1872,9 +1923,9 @@ } }, "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -1964,6 +2015,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -1998,15 +2058,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", - "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -2049,6 +2100,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -2067,6 +2137,16 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2131,9 +2211,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", "dev": true }, "node_modules/levn": { @@ -2389,10 +2469,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/minimist-options": { "version": "4.1.0", @@ -2475,14 +2558,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -2493,14 +2576,14 @@ } }, "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -2665,9 +2748,9 @@ } }, "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "dev": true, "funding": [ { @@ -2717,25 +2800,31 @@ } }, "node_modules/postcss-scss": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.4.tgz", - "integrity": "sha512-aBBbVyzA8b3hUL0MGrpydxxXKXFZc5Eqva0Q3V9qsBOLEMsjb6w49WfpsoWzpEgcqJGW4t7Rio8WXVU9Gd8vWg==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.6.tgz", + "integrity": "sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + } + ], "engines": { "node": ">=12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { - "postcss": "^8.3.3" + "postcss": "^8.4.19" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -3051,29 +3140,32 @@ } }, "node_modules/rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.0.0.tgz", + "integrity": "sha512-j6oypPP+mgFwDXL1JkLCtm6U/DQntMUqlv5SOhpgHhdIE+PmBcjrtAHIpXfbIup47kD5Sgja9JDsDF1NNOsBwQ==", "dev": true, "dependencies": { - "find-up": "^5.0.0", + "escalade": "^3.1.1", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.6", "strip-json-comments": "^3.1.1" }, "bin": { "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" } }, "node_modules/run-con": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.10.tgz", - "integrity": "sha512-n7PZpYmMM26ZO21dd8y3Yw1TRtGABjRtgPSgFS/nhzfvbJMXFtJhJVyEgayMiP+w/23craJjsnfDvx4W4ue/HQ==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.11.tgz", + "integrity": "sha512-NEMGsUT+cglWkzEr4IFK21P4Jca45HqiAbIIZIBdX5+UZTB24Mb/21iNGgz9xZa8tL6vbW7CXmq7MFN42+VjNQ==", "dev": true, "dependencies": { "deep-extend": "^0.6.0", - "ini": "~2.0.0", - "minimist": "^1.2.5", + "ini": "~3.0.0", + "minimist": "^1.2.6", "strip-json-comments": "~3.1.1" }, "bin": { @@ -3103,10 +3195,24 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sass": { - "version": "1.52.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.3.tgz", - "integrity": "sha512-LNNPJ9lafx+j1ArtA7GyEJm9eawXN8KlA1+5dF6IZyoONg1Tyo/g+muOsENWJH/2Q1FHbbV4UwliU0cXMa/VIA==", + "version": "1.57.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", + "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -3121,9 +3227,9 @@ } }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3238,9 +3344,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "node_modules/string-width": { @@ -3258,28 +3364,28 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3337,51 +3443,49 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.9.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.9.1.tgz", - "integrity": "sha512-RdAkJdPiLqHawCSnu21nE27MjNXaVd4WcOHA4vK5GtIGjScfhNnaOuWR2wWdfKFAvcWQPOYe311iveiVKSmwsA==", + "version": "14.16.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.1.tgz", + "integrity": "sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A==", "dev": true, "dependencies": { - "@csstools/selector-specificity": "^2.0.1", + "@csstools/selector-specificity": "^2.0.2", "balanced-match": "^2.0.0", - "colord": "^2.9.2", - "cosmiconfig": "^7.0.1", + "colord": "^2.9.3", + "cosmiconfig": "^7.1.0", "css-functions-list": "^3.1.0", "debug": "^4.3.4", - "execall": "^2.0.0", - "fast-glob": "^3.2.11", - "fastest-levenshtein": "^1.0.12", + "fast-glob": "^3.2.12", + "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^6.0.1", - "get-stdin": "^8.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.2.0", - "ignore": "^5.2.0", + "ignore": "^5.2.1", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", + "known-css-properties": "^0.26.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.14", + "postcss": "^8.4.19", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", - "supports-hyperlinks": "^2.2.0", + "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", - "table": "^6.8.0", + "table": "^6.8.1", "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "bin": { "stylelint": "bin/stylelint.js" @@ -3395,26 +3499,32 @@ } }, "node_modules/stylelint-config-recommended": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", - "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", + "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", "dev": true, "peerDependencies": { - "stylelint": "^14.4.0" + "stylelint": "^14.10.0" } }, "node_modules/stylelint-config-recommended-scss": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-6.0.0.tgz", - "integrity": "sha512-6QOe2/OzXV2AP5FE12A7+qtKdZik7Saf42SMMl84ksVBBPpTdrV+9HaCbPYiRMiwELY9hXCVdH4wlJ+YJb5eig==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-8.0.0.tgz", + "integrity": "sha512-BxjxEzRaZoQb7Iinc3p92GS6zRdRAkIuEu2ZFLTxJK2e1AIcCb5B5MXY9KOXdGTnYFZ+KKx6R4Fv9zU6CtMYPQ==", "dev": true, "dependencies": { "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^7.0.0", + "stylelint-config-recommended": "^9.0.0", "stylelint-scss": "^4.0.0" }, "peerDependencies": { - "stylelint": "^14.4.0" + "postcss": "^8.3.3", + "stylelint": "^14.10.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, "node_modules/stylelint-order": { @@ -3431,9 +3541,9 @@ } }, "node_modules/stylelint-scss": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.2.0.tgz", - "integrity": "sha512-HHHMVKJJ5RM9pPIbgJ/XA67h9H0407G68Rm69H4fzFbFkyDMcTV1Byep3qdze5+fJ3c0U7mJrbj6S0Fg072uZA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.3.0.tgz", + "integrity": "sha512-GvSaKCA3tipzZHoz+nNO7S02ZqOsdBzMiCx9poSmLlb3tdJlGddEX/8QzCOD8O7GQan9bjsvLMsO5xiw6IhhIQ==", "dev": true, "dependencies": { "lodash": "^4.17.21", @@ -3452,18 +3562,6 @@ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, - "node_modules/stylelint/node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -3486,9 +3584,9 @@ } }, "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dev": true, "dependencies": { "has-flag": "^4.0.0", @@ -3517,9 +3615,9 @@ "dev": true }, "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -3533,9 +3631,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -3617,6 +3715,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -3700,6 +3812,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -3716,16 +3848,16 @@ "dev": true }, "node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/yallist": { @@ -3767,27 +3899,27 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.18.6" } }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, "@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -3851,22 +3983,22 @@ } }, "@csstools/selector-specificity": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz", - "integrity": "sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", "dev": true, "requires": {} }, "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", + "espree": "^9.4.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -3875,16 +4007,22 @@ } }, "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "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": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -3942,9 +4080,9 @@ "dev": true }, "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "acorn-jsx": { @@ -3982,9 +4120,9 @@ } }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -3998,15 +4136,15 @@ "dev": true }, "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" } }, @@ -4017,14 +4155,14 @@ "dev": true }, "array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" } }, @@ -4040,6 +4178,12 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4150,15 +4294,6 @@ } } }, - "clone-regexp": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", - "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==", - "dev": true, - "requires": { - "is-regexp": "^2.0.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4175,9 +4310,9 @@ "dev": true }, "colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "dev": true }, "commander": { @@ -4193,9 +4328,9 @@ "dev": true }, "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", @@ -4244,9 +4379,9 @@ "dev": true }, "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, "requires": { "decamelize": "^1.1.0", @@ -4323,34 +4458,54 @@ } }, "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.0.tgz", + "integrity": "sha512-GUGtW7eXQay0c+PRq0sGIKSdaBorfVqsCMhGHo4elP7YVqZu9nCZS4UkK4gv71gOWNMra/PaSKD3ao1oWExO0g==", "dev": true, "requires": { "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.0", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.0", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" } }, "es-shim-unscopables": { @@ -4373,6 +4528,12 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4380,13 +4541,15 @@ "dev": true }, "eslint": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.18.0.tgz", - "integrity": "sha512-As1EfFMVk7Xc6/CvhssHUjsAQSkpfXvUGMFC3ce8JDe6WvqCgRrLOBQbVpsBFr1X1V+RACOadnzVvcUS5ni2bA==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -4396,18 +4559,21 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -4418,8 +4584,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" } }, "eslint-config-standard": { @@ -4451,13 +4616,12 @@ } }, "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "dependencies": { "debug": { @@ -4468,55 +4632,6 @@ "requires": { "ms": "^2.1.1" } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true } } }, @@ -4595,25 +4710,25 @@ } }, "eslint-plugin-n": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.2.3.tgz", - "integrity": "sha512-H+KC7U5R+3IWTeRnACm/4wlqLvS1Q7M6t7BGhn89qXDkZan8HTAEv3ouIONA0ifDwc2YzPFmyPzHuNLddNK4jw==", + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.0.tgz", + "integrity": "sha512-Hd/F7wz4Mj44Jp0H6Jtty13NcE69GNTY0rVlgTIj1XBnGGVI6UTdDrpE6vqu3AHo07bygq/N+7OH/lgz1emUJw==", "dev": true, "requires": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", "eslint-utils": "^3.0.0", "ignore": "^5.1.1", - "is-core-module": "^2.9.0", + "is-core-module": "^2.11.0", "minimatch": "^3.1.2", - "resolve": "^1.10.1", - "semver": "^7.3.7" + "resolve": "^1.22.1", + "semver": "^7.3.8" } }, "eslint-plugin-promise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", - "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", "dev": true, "requires": {} }, @@ -4651,12 +4766,12 @@ "dev": true }, "espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { - "acorn": "^8.7.1", + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" } @@ -4691,15 +4806,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "execall": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", - "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", - "dev": true, - "requires": { - "clone-regexp": "^2.1.0" - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4707,9 +4813,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -4743,15 +4849,15 @@ "dev": true }, "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -4796,11 +4902,20 @@ } }, "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4832,12 +4947,6 @@ "functions-have-names": "^1.2.2" } }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -4845,9 +4954,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -4932,14 +5041,23 @@ } }, "globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, "globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -4960,6 +5078,21 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -4996,6 +5129,12 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -5027,15 +5166,15 @@ "dev": true }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "immutable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", - "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", + "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==", "dev": true }, "import-fresh": { @@ -5083,22 +5222,33 @@ "dev": true }, "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", "dev": true }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" } }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5134,15 +5284,15 @@ } }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -5199,6 +5349,12 @@ "has-tostringtag": "^1.0.0" } }, + "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 + }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -5221,12 +5377,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-regexp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", - "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==", - "dev": true - }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -5254,6 +5404,19 @@ "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -5269,6 +5432,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5324,9 +5493,9 @@ "dev": true }, "known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", "dev": true }, "levn": { @@ -5525,9 +5694,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "minimist-options": { @@ -5590,26 +5759,26 @@ "dev": true }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "once": { @@ -5723,9 +5892,9 @@ "dev": true }, "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "dev": true, "requires": { "nanoid": "^3.3.4", @@ -5753,16 +5922,16 @@ "requires": {} }, "postcss-scss": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.4.tgz", - "integrity": "sha512-aBBbVyzA8b3hUL0MGrpydxxXKXFZc5Eqva0Q3V9qsBOLEMsjb6w49WfpsoWzpEgcqJGW4t7Rio8WXVU9Gd8vWg==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.6.tgz", + "integrity": "sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==", "dev": true, "requires": {} }, "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -5981,26 +6150,26 @@ } }, "rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.0.0.tgz", + "integrity": "sha512-j6oypPP+mgFwDXL1JkLCtm6U/DQntMUqlv5SOhpgHhdIE+PmBcjrtAHIpXfbIup47kD5Sgja9JDsDF1NNOsBwQ==", "dev": true, "requires": { - "find-up": "^5.0.0", + "escalade": "^3.1.1", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.6", "strip-json-comments": "^3.1.1" } }, "run-con": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.10.tgz", - "integrity": "sha512-n7PZpYmMM26ZO21dd8y3Yw1TRtGABjRtgPSgFS/nhzfvbJMXFtJhJVyEgayMiP+w/23craJjsnfDvx4W4ue/HQ==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.11.tgz", + "integrity": "sha512-NEMGsUT+cglWkzEr4IFK21P4Jca45HqiAbIIZIBdX5+UZTB24Mb/21iNGgz9xZa8tL6vbW7CXmq7MFN42+VjNQ==", "dev": true, "requires": { "deep-extend": "^0.6.0", - "ini": "~2.0.0", - "minimist": "^1.2.5", + "ini": "~3.0.0", + "minimist": "^1.2.6", "strip-json-comments": "~3.1.1" } }, @@ -6013,10 +6182,21 @@ "queue-microtask": "^1.2.2" } }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "sass": { - "version": "1.52.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.3.tgz", - "integrity": "sha512-LNNPJ9lafx+j1ArtA7GyEJm9eawXN8KlA1+5dF6IZyoONg1Tyo/g+muOsENWJH/2Q1FHbbV4UwliU0cXMa/VIA==", + "version": "1.57.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", + "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -6025,9 +6205,9 @@ } }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -6115,9 +6295,9 @@ } }, "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "string-width": { @@ -6132,25 +6312,25 @@ } }, "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "strip-ansi": { @@ -6190,51 +6370,49 @@ "dev": true }, "stylelint": { - "version": "14.9.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.9.1.tgz", - "integrity": "sha512-RdAkJdPiLqHawCSnu21nE27MjNXaVd4WcOHA4vK5GtIGjScfhNnaOuWR2wWdfKFAvcWQPOYe311iveiVKSmwsA==", + "version": "14.16.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.1.tgz", + "integrity": "sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A==", "dev": true, "requires": { - "@csstools/selector-specificity": "^2.0.1", + "@csstools/selector-specificity": "^2.0.2", "balanced-match": "^2.0.0", - "colord": "^2.9.2", - "cosmiconfig": "^7.0.1", + "colord": "^2.9.3", + "cosmiconfig": "^7.1.0", "css-functions-list": "^3.1.0", "debug": "^4.3.4", - "execall": "^2.0.0", - "fast-glob": "^3.2.11", - "fastest-levenshtein": "^1.0.12", + "fast-glob": "^3.2.12", + "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^6.0.1", - "get-stdin": "^8.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.2.0", - "ignore": "^5.2.0", + "ignore": "^5.2.1", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", + "known-css-properties": "^0.26.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.14", + "postcss": "^8.4.19", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", - "supports-hyperlinks": "^2.2.0", + "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", - "table": "^6.8.0", + "table": "^6.8.1", "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "dependencies": { "balanced-match": { @@ -6243,12 +6421,6 @@ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -6258,20 +6430,20 @@ } }, "stylelint-config-recommended": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", - "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", + "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", "dev": true, "requires": {} }, "stylelint-config-recommended-scss": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-6.0.0.tgz", - "integrity": "sha512-6QOe2/OzXV2AP5FE12A7+qtKdZik7Saf42SMMl84ksVBBPpTdrV+9HaCbPYiRMiwELY9hXCVdH4wlJ+YJb5eig==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-8.0.0.tgz", + "integrity": "sha512-BxjxEzRaZoQb7Iinc3p92GS6zRdRAkIuEu2ZFLTxJK2e1AIcCb5B5MXY9KOXdGTnYFZ+KKx6R4Fv9zU6CtMYPQ==", "dev": true, "requires": { "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^7.0.0", + "stylelint-config-recommended": "^9.0.0", "stylelint-scss": "^4.0.0" } }, @@ -6286,9 +6458,9 @@ } }, "stylelint-scss": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.2.0.tgz", - "integrity": "sha512-HHHMVKJJ5RM9pPIbgJ/XA67h9H0407G68Rm69H4fzFbFkyDMcTV1Byep3qdze5+fJ3c0U7mJrbj6S0Fg072uZA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.3.0.tgz", + "integrity": "sha512-GvSaKCA3tipzZHoz+nNO7S02ZqOsdBzMiCx9poSmLlb3tdJlGddEX/8QzCOD8O7GQan9bjsvLMsO5xiw6IhhIQ==", "dev": true, "requires": { "lodash": "^4.17.21", @@ -6308,9 +6480,9 @@ } }, "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -6330,9 +6502,9 @@ "dev": true }, "table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -6343,9 +6515,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -6410,6 +6582,17 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -6481,6 +6664,20 @@ "is-symbol": "^1.0.3" } }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -6494,9 +6691,9 @@ "dev": true }, "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "requires": { "imurmurhash": "^0.1.4", diff --git a/package.json b/package.json index fe25a3f43..fc3e3c150 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,9 @@ "url": "https://github.com/FreshRSS/FreshRSS.git" }, "license": "AGPL-3.0", + "engines" : { + "node" : ">=12" + }, "scripts": { "eslint": "eslint --ext .js .", "eslint_fix": "eslint --fix --ext .js .", @@ -30,16 +33,16 @@ "fix": "npm run rtlcss && npm run stylelint_fix && npm run eslint_fix && npm run markdownlint_fix" }, "devDependencies": { - "eslint": "^8.10.0", + "eslint": "^8.31.0", "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.2.3", - "eslint-plugin-promise": "^6.0.0", + "eslint-plugin-n": "^15.6.0", + "eslint-plugin-promise": "^6.1.1", "markdownlint-cli": "^0.31.1", - "rtlcss": "^3.5.0", - "sass": "^1.52.3", - "stylelint": "^14.9.0", - "stylelint-config-recommended-scss": "^6.0.0", + "rtlcss": "^4.0.0", + "sass": "^1.57.0", + "stylelint": "^14.16.1", + "stylelint-config-recommended-scss": "^8.0.0", "stylelint-order": "^5.0.0" }, "rtlcssConfig": {} diff --git a/tests/app/Models/UserQueryTest.php b/tests/app/Models/UserQueryTest.php index c876740e6..d56c4b743 100644 --- a/tests/app/Models/UserQueryTest.php +++ b/tests/app/Models/UserQueryTest.php @@ -34,7 +34,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { ->method('name') ->withAnyParameters() ->willReturn($category_name); - $cat_dao = $this->createMock('FreshRSS_Searchable'); + $cat_dao = $this->createMock('FreshRSS_CategoryDAO'); $cat_dao->expects($this->atLeastOnce()) ->method('searchById') ->withAnyParameters() @@ -60,7 +60,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { ->method('name') ->withAnyParameters() ->willReturn($feed_name); - $feed_dao = $this->createMock('FreshRSS_Searchable'); + $feed_dao = $this->createMock('FreshRSS_FeedDAO'); $feed_dao->expects($this->atLeastOnce()) ->method('searchById') ->withAnyParameters() @@ -160,7 +160,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { public function testIsDeprecated_whenCategoryExists_returnFalse() { $cat = $this->createMock('FreshRSS_Category'); - $cat_dao = $this->createMock('FreshRSS_Searchable'); + $cat_dao = $this->createMock('FreshRSS_CategoryDAO'); $cat_dao->expects($this->atLeastOnce()) ->method('searchById') ->withAnyParameters() @@ -171,7 +171,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { } public function testIsDeprecated_whenCategoryDoesNotExist_returnTrue() { - $cat_dao = $this->createMock('FreshRSS_Searchable'); + $cat_dao = $this->createMock('FreshRSS_CategoryDAO'); $cat_dao->expects($this->atLeastOnce()) ->method('searchById') ->withAnyParameters() @@ -183,7 +183,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { public function testIsDeprecated_whenFeedExists_returnFalse() { $feed = $this->createMock('FreshRSS_Feed', array(), array('', false)); - $feed_dao = $this->createMock('FreshRSS_Searchable'); + $feed_dao = $this->createMock('FreshRSS_FeedDAO'); $feed_dao->expects($this->atLeastOnce()) ->method('searchById') ->withAnyParameters() @@ -194,7 +194,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { } public function testIsDeprecated_whenFeedDoesNotExist_returnTrue() { - $feed_dao = $this->createMock('FreshRSS_Searchable'); + $feed_dao = $this->createMock('FreshRSS_FeedDAO'); $feed_dao->expects($this->atLeastOnce()) ->method('searchById') ->withAnyParameters() -- cgit v1.2.3 From e67ca8c86672edff7849965fc7cf85af56340983 Mon Sep 17 00:00:00 2001 From: maTh Date: Tue, 17 Jan 2023 15:36:43 +0100 Subject: documentation improved: split en/users/03_Main_view.md into 3 parts (#5013) * documentation * update the links * fix --- docs/en/admins/08_FeedUpdates.md | 2 +- docs/en/users/02_First_steps.md | 6 +- docs/en/users/03_Main_view.md | 263 ++--------------------------------- docs/en/users/04_Subscriptions.md | 2 +- docs/en/users/09_refreshing_feeds.md | 103 ++++++++++++++ docs/en/users/10_filter.md | 152 ++++++++++++++++++++ 6 files changed, 271 insertions(+), 257 deletions(-) create mode 100644 docs/en/users/09_refreshing_feeds.md create mode 100644 docs/en/users/10_filter.md (limited to 'docs/en') diff --git a/docs/en/admins/08_FeedUpdates.md b/docs/en/admins/08_FeedUpdates.md index 2072188bd..79c2bbea6 100644 --- a/docs/en/admins/08_FeedUpdates.md +++ b/docs/en/admins/08_FeedUpdates.md @@ -6,7 +6,7 @@ FreshRSS is updated by the `./app/actualize_script.php` script. Knowing this, we **Note:** the following examples assume that FreshRSS is installed to `/usr/share/FreshRSS`. You’ll need to modify the FreshRSS path to reflect your own system. -**Note:** If you cannot configure a local Cronjob, [see an alternative using online cron](../users/03_Main_view.md#online-cron). +**Note:** If you cannot configure a local Cronjob, [see an alternative using online cron](../users/09_refreshing_feeds.md#online-cron). ## Cron as a trigger diff --git a/docs/en/users/02_First_steps.md b/docs/en/users/02_First_steps.md index 3bcdaab08..7f176af77 100644 --- a/docs/en/users/02_First_steps.md +++ b/docs/en/users/02_First_steps.md @@ -19,9 +19,9 @@ Now that you’ve mastered basic use, it’s time to configure FreshRSS to impro * [Organize your feeds in categories](04_Subscriptions.md#feed-management) * [Change the home page](05_Configuration.md#changing-the-view) * [Choose the reading options](05_Configuration.md#reading-options) -* [Refresh feeds](03_Main_view.md#refreshing-feeds) -* [Filter articles](03_Main_view.md#filtering-articles) for a fast access to a selection -* [search for an article](03_Main_view.md#with-the-search-field) published some time ago +* [Refresh feeds](09_refreshing_feeds.md) +* [Filter articles](10_filter.md) for a fast access to a selection +* [search for an article](10_filter.md#with-the-search-field) published some time ago * [Access your feeds on a mobile device](06_Mobile_access.md) * [Add some extensions](https://github.com/FreshRSS/Extensions) * [Frequently asked questions](07_Frequently_Asked_Questions.md) diff --git a/docs/en/users/03_Main_view.md b/docs/en/users/03_Main_view.md index d940774f5..7a0320cb6 100644 --- a/docs/en/users/03_Main_view.md +++ b/docs/en/users/03_Main_view.md @@ -1,10 +1,12 @@ +# Views + FreshRSS has three primary viewing modes: Normal, Global, and Reader view. -# Normal view +## Normal view Normal view will allow you to view articles in a compressed view. They can be separated by category or individual feed, or viewed in the "main stream" containing all feeds. Clicking a feed in the sidebar (mobile users will need to click the folder icon to open it) will open that feed’s view. -## Article List +### Article List By default, the normal view includes six items per article. From left to right: * **Read status:** An envelope icon to show if the article has been read or not. Closed envelopes are unread, open envelopes are read. Clicking on the icon will toggle the read status. @@ -14,7 +16,7 @@ By default, the normal view includes six items per article. From left to right: * **Article date/time:** The time the article was posted. * **Link to original article:** A globe icon that can be clicked to go to the article on the original website. -## Normal View Sidebar +### Normal View Sidebar Clicking the gear icon next to an individual feed will display additional options for that feed. * **Filter:** Run the defined filter to mark articles as read @@ -24,258 +26,15 @@ Clicking the gear icon next to an individual feed will display additional option * **Actualize:** Force-update the feed * **Mark as read:** Mark all items in the feed as read -# Global view +## Global view Global view allows quick views of feed’s statuses at once. Feeds and categories are shown with the number of unread articles next to them. Clicking a feed’s name will open it in a view similar to normal view. -# Reader view +## Reader view Reader view will display a feed will all articles already open for reading. Feeds can be switched by clicking the folder icon at the top to bring up the category/feed sidebar. -# Refreshing feeds - -To take full advantage of FreshRSS, it needs to retrieve new items from the feeds you have subscribed to. There are several ways to do this. - -## Automatic update with cron - -This is the recommended method. - -This method is only available if you have access to the scheduled tasks of the machine on which your FreshRSS instance is installed. - -The script is named *actualize_script.php* and is located in the *app* folder. The scheduled task syntax will not be explained here. However, here is [a quick introduction to crontab](http://www.adminschoice.com/crontab-quick-reference/) that might help you. - -Here is an example to trigger article update every hour. - -```cron -0 * * * * php /path/to/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1 -``` - -## Online cron - -If you do not have access to the installation server scheduled task, you can still automate the update process. - -To do so, you need to create a scheduled task, which need to call a specific URL: - (it could be different depending on your installation). Depending on your application authentication method, you need to adapt the scheduled task. - -Special parameters to configure the script - all parameters can be combined: - -* Parameter "force" - -If *force* is set to 1 all feeds will be refreshed at once. - -* Parameter "ajax" - -Only a status site is returned and not a complete website. Example: "OK" - -* Parameter "maxFeeds" - -If *maxFeeds* is set the configured amount of feeds is refreshed at once. The default setting is "10". - -* Parameter "token" - -Security parameter to prevent unauthorized refreshes. For detailed Documentation see "Form authentication". - -### For Form Authentication - -If your FreshRSS instance is using Form Authentication, you can configure an authentication token to grant access to the online cron. - -![Token configuration](../img/users/token.1.png) - -You can target a specific user by adding their username to the query string, with `&user=insert-username`: - -The scheduled task syntax should look as follows: - - - -Alternatively, but not recommended, if you configure the application to allow anonymous reading, you can also allow anonymous users to update feeds (“Allow anonymous refresh of the articles”), and that does not require a token. - -![Anonymous access configuration](../img/users/anonymous_access.1.png) - -### For HTTP authentication - -If your FreshRSS instance is using HTTP authentication, you’ll need to provide your credentials to the scheduled task. - -**Note:** This method is discouraged as your credentials are stored in plain text. - -```cron -0 * * * * curl -u alice:password123 'https://freshrss.example.net/i/?c=feed&a=actualize&maxFeeds=10&ajax=1&user=alice' -``` - -On some systems, that syntax might also work: - - - -### For No authentication (None) - -If your FreshRSS instance uses no authentication (public instance, default user): - - - -## Manual update - -If you can’t or don’t want to use the automatic method, you can update manually. There are two methods for updating all or some of the feeds. - -### Complete update - -This update occurs on all feeds. To trigger it, simply click on the update link in the navigation menu. - -![Navigation menu](../img/users/refresh.1.png) - -When the update starts, a progress bar appears and changes while feeds are processed. - -![Progress bar](../img/users/refresh.5.png) - -### Partial update - -This update occurs on the selected feed only. To trigger it, simply click on the update link in the feed menu. - -![Feed menu](../img/users/refresh.2.png) - -# Filtering articles - -## Purpose - -When the number of articles stored by FreshRSS inevitably grows larger, it’s important to use efficient filters to display only a subset of the articles. There are several methods that filter with different criteria. Usually those methods can be combined. - -## How-to filter - -### By category - -This is the easiest method. You only need to click on the category title in the side panel. There are two special categories at the top of the panel: - -* *Main feed* displays only articles from feeds marked as available in that category -* *Favourites* displays only articles marked as favourites - -### By feed - -There are several methods to filter articles by feed: - -* by clicking the feed title in the side panel -* by clicking the feed title in the article details -* by filtering in the feed options from the side panel -* by filtering in the feed configuration - -![Feed filter](../img/users/feed.filter.1.png) - -### By status - -Each article has two attributes that can be combined. The first attribute indicates whether or not the article has been read. The second attribute indicates if the article was marked as favorite or not. - -In version 0.7, attribute filters are available in the article display dropdown list. With this version, it’s not possible to combine filters. For instance, it’s not possible to display only read and favorite articles. - -![Attribute filters in 0.7](../img/users/status.filter.0.7.png) - -Starting with version 0.8, all attribute filters are visible as toggle icons. They can be combined. As any combination is possible, some have the same result. For instance, the result for all filters selected is the same as no filter selected. - -![Attribute filters in 0.8](../img/users/status.filter.0.8.png) - -By default, this filter displays only unread articles - -### By content - -It is possible to filter articles by their content by inputting a string in the search field. - -### With the search field - -You can use the search field to further refine results: - -* by feed ID: `f:123` or multiple feed IDs (*or*): `f:123,234,345` -* by author: `author:name` or `author:'composed name'` -* by title: `intitle:keyword` or `intitle:'composed keyword'` -* by URL: `inurl:keyword` or `inurl:'composed keyword'` -* by tag: `#tag` or `#tag+with+whitespace` -* by free-text: `keyword` or `'composed keyword'` -* by date of discovery, using the [ISO 8601 time interval format](http://en.wikipedia.org/wiki/ISO_8601#Time_intervals): `date:` - * From a specific day, or month, or year: - * `date:2014-03-30` - * `date:2014-03` or `date:201403` - * `date:2014` - * From a specific time of a given day: - * `date:2014-05-30T13` - * `date:2014-05-30T13:30` - * Between two given dates: - * `date:2014-02/2014-04` - * `date:2014-02--2014-04` - * `date:2014-02/04` - * `date:2014-02-03/05` - * `date:2014-02-03T22:00/22:15` - * `date:2014-02-03T22:00/15` - * After a given date: - * `date:2014-03/` - * Before a given date: - * `date:/2014-03` - * For a specific duration after a given date: - * `date:2014-03/P1W` - * For a specific duration before a given date: - * `date:P1W/2014-05-25T23:59:59` - * For the past duration before now (the trailing slash is optional): - * `date:P1Y/` or `date:P1Y` (past year) - * `date:P2M/` (past two months) - * `date:P3W/` (past three weeks) - * `date:P4D/` (past four days) - * `date:PT5H/` (past five hours) - * `date:PT30M/` (past thirty minutes) - * `date:PT90S/` (past ninety seconds) - * `date:P1DT1H/` (past one day and one hour) -* by date of publication, using the same format: `pubdate:` -* by custom label ID `L:12` or multiple label IDs: `L:12,13,14` or with any label: `L:*` -* by custom label name `label:label`, `label:"my label"` or any label name from a list (*or*): `labels:"my label,my other label"` -* by several label names (*and*): `label:"my label" label:"my other label"` -* by entry (article) ID: `e:1639310674957894` or multiple entry IDs (*or*): `e:1639310674957894,1639310674957893` -* by user query (saved search) name: `search:myQuery`, `search:"My query"` or saved search ID: `S:3` - * internally, those references are replaced by the corresponding user query in the search expression - -Be careful not to enter a space between the operator and the search value. - -Some operators can be used negatively, to exclude articles, with the same syntax as above, but prefixed by a `!` or `-`: -`!f:234`, `-author:name`, `-intitle:keyword`, `-inurl:keyword`, `-#tag`, `!keyword`, `!date:2019`, `!date:P1W`, `!pubdate:P3d/`. - -It is also possible to combine keywords to create a more precise filter. -For example, you can enter multiple instances of `f:`, `author:`, `intitle:`, `inurl:`, `#`, and free-text. - -Combining several search criteria implies a logical *and*, but the keyword ` OR ` -can be used to combine several search criteria with a logical *or* instead: `author:Dupont OR author:Dupond` - -You don’t have to do anything special to combine multiple negative operators. Writing `!intitle:'thing1' !intitle:'thing2'` implies AND, see above. For more pointers on how AND and OR interact with negation, see [this GitHub comment](https://github.com/FreshRSS/FreshRSS/issues/3236#issuecomment-891219460). -Additional reading: [De Morgan's laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). - -Finally, parentheses may be used to express more complex queries, with basic negation support: - -* `(author:Alice OR intitle:hello) (author:Bob OR intitle:world)` -* `(author:Alice intitle:hello) OR (author:Bob intitle:world)` -* `!((author:Alice intitle:hello) OR (author:Bob intitle:world))` -* `(author:Alice intitle:hello) !(author:Bob intitle:world)` -* `!(S:1 OR S:2)` - -> ℹ️ If you need to search for a parenthesis, it needs to be escaped like `\(` or `\)` - -### By sorting by date - -You can change the sort order by clicking the toggle button available in the header. - -## Store your filters - -Once you came up with your perfect filter, it would be a shame if you need to recreate it every time you need to use it. - -Hopefully, there is a way to bookmark them for later use. -We call them *user queries*. -You can create as many as you want, the only limit is how they will be displayed on your screen. - -### Bookmark the current query - -Display the user queries drop-down by clicking the button next to the state buttons. -![User queries drop-down](../img/users/user.queries.drop-down.empty.png) - -Then click on the bookmark action. - -Congratulations, you’re done! - -### Using a bookmarked query - -Display the user queries drop-down by clicking the button next to the state buttons. -![User queries drop-down](../img/users/user.queries.drop-down.not.empty.png) - -Then click on the bookmarked query, the previously stored query will be applied. - -> Note that only the query is stored, not the articles. -> The results you are seeing now could be different from the results on the day you've created the query. +--- +Read more: +* [Refreshing the feeds](./09_refreshing_feeds.md) +* [Filter the feeds and search](./10_filter.md) diff --git a/docs/en/users/04_Subscriptions.md b/docs/en/users/04_Subscriptions.md index d50d92bf2..a6b54ffe8 100644 --- a/docs/en/users/04_Subscriptions.md +++ b/docs/en/users/04_Subscriptions.md @@ -89,7 +89,7 @@ Complementary tools can be used to retrieve full article content, such as: ### Filter -Articles can be automatically marked as read based on some search terms. See [filtering](./03_Main_view.md#filtering-articles) for more information on how to create these filters. +Articles can be automatically marked as read based on some search terms. See [filtering](./10_filter.md) for more information on how to create these filters. ## Import / export diff --git a/docs/en/users/09_refreshing_feeds.md b/docs/en/users/09_refreshing_feeds.md new file mode 100644 index 000000000..ec20c7d62 --- /dev/null +++ b/docs/en/users/09_refreshing_feeds.md @@ -0,0 +1,103 @@ +# Refreshing feeds + +To take full advantage of FreshRSS, it needs to retrieve new items from the feeds you have subscribed to. There are several ways to do this. + +## Automatic update with cron + +This is the recommended method. + +This method is only available if you have access to the scheduled tasks of the machine on which your FreshRSS instance is installed. + +The script is named *actualize_script.php* and is located in the *app* folder. The scheduled task syntax will not be explained here. However, here is [a quick introduction to crontab](http://www.adminschoice.com/crontab-quick-reference/) that might help you. + +Here is an example to trigger article update every hour. + +```cron +0 * * * * php /path/to/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1 +``` + +## Online cron + +If you do not have access to the installation server scheduled task, you can still automate the update process. + +To do so, you need to create a scheduled task, which need to call a specific URL: + (it could be different depending on your installation). Depending on your application authentication method, you need to adapt the scheduled task. + +Special parameters to configure the script - all parameters can be combined: + +* Parameter "force" + +If *force* is set to 1 all feeds will be refreshed at once. + +* Parameter "ajax" + +Only a status site is returned and not a complete website. Example: "OK" + +* Parameter "maxFeeds" + +If *maxFeeds* is set the configured amount of feeds is refreshed at once. The default setting is "10". + +* Parameter "token" + +Security parameter to prevent unauthorized refreshes. For detailed Documentation see "Form authentication". + +### For Form Authentication + +If your FreshRSS instance is using Form Authentication, you can configure an authentication token to grant access to the online cron. + +![Token configuration](../img/users/token.1.png) + +You can target a specific user by adding their username to the query string, with `&user=insert-username`: + +The scheduled task syntax should look as follows: + + + +Alternatively, but not recommended, if you configure the application to allow anonymous reading, you can also allow anonymous users to update feeds (“Allow anonymous refresh of the articles”), and that does not require a token. + +![Anonymous access configuration](../img/users/anonymous_access.1.png) + +### For HTTP authentication + +If your FreshRSS instance is using HTTP authentication, you’ll need to provide your credentials to the scheduled task. + +**Note:** This method is discouraged as your credentials are stored in plain text. + +```cron +0 * * * * curl -u alice:password123 'https://freshrss.example.net/i/?c=feed&a=actualize&maxFeeds=10&ajax=1&user=alice' +``` + +On some systems, that syntax might also work: + + + +### For No authentication (None) + +If your FreshRSS instance uses no authentication (public instance, default user): + + + +## Manual update + +If you can’t or don’t want to use the automatic method, you can update manually. There are two methods for updating all or some of the feeds. + +### Complete update + +This update occurs on all feeds. To trigger it, simply click on the update link in the navigation menu. + +![Navigation menu](../img/users/refresh.1.png) + +When the update starts, a progress bar appears and changes while feeds are processed. + +![Progress bar](../img/users/refresh.5.png) + +### Partial update + +This update occurs on the selected feed only. To trigger it, simply click on the update link in the feed menu. + +![Feed menu](../img/users/refresh.2.png) + +--- +Read more: +* [Normal, Global and Reader view](./03_Main_view.md) +* [Filter the feeds and search](./10_filter.md) diff --git a/docs/en/users/10_filter.md b/docs/en/users/10_filter.md new file mode 100644 index 000000000..2e69b97f8 --- /dev/null +++ b/docs/en/users/10_filter.md @@ -0,0 +1,152 @@ + +# Filtering articles + +## Purpose + +When the number of articles stored by FreshRSS inevitably grows larger, it’s important to use efficient filters to display only a subset of the articles. There are several methods that filter with different criteria. Usually those methods can be combined. + +## By category + +This is the easiest method. You only need to click on the category title in the side panel. There are two special categories at the top of the panel: + +* *Main feed* displays only articles from feeds marked as available in that category +* *Favourites* displays only articles marked as favourites + +## By feed + +There are several methods to filter articles by feed: + +* by clicking the feed title in the side panel +* by clicking the feed title in the article details +* by filtering in the feed options from the side panel +* by filtering in the feed configuration + +![Feed filter](../img/users/feed.filter.1.png) + +## By status + +Each article has two attributes that can be combined. The first attribute indicates whether or not the article has been read. The second attribute indicates if the article was marked as favorite or not. + +In version 0.7, attribute filters are available in the article display dropdown list. With this version, it’s not possible to combine filters. For instance, it’s not possible to display only read and favorite articles. + +![Attribute filters in 0.7](../img/users/status.filter.0.7.png) + +Starting with version 0.8, all attribute filters are visible as toggle icons. They can be combined. As any combination is possible, some have the same result. For instance, the result for all filters selected is the same as no filter selected. + +![Attribute filters in 0.8](../img/users/status.filter.0.8.png) + +By default, this filter displays only unread articles + +## By content + +It is possible to filter articles by their content by inputting a string in the search field. + +## With the search field + +You can use the search field to further refine results: + +* by feed ID: `f:123` or multiple feed IDs (*or*): `f:123,234,345` +* by author: `author:name` or `author:'composed name'` +* by title: `intitle:keyword` or `intitle:'composed keyword'` +* by URL: `inurl:keyword` or `inurl:'composed keyword'` +* by tag: `#tag` or `#tag+with+whitespace` +* by free-text: `keyword` or `'composed keyword'` +* by date of discovery, using the [ISO 8601 time interval format](http://en.wikipedia.org/wiki/ISO_8601#Time_intervals): `date:` + * From a specific day, or month, or year: + * `date:2014-03-30` + * `date:2014-03` or `date:201403` + * `date:2014` + * From a specific time of a given day: + * `date:2014-05-30T13` + * `date:2014-05-30T13:30` + * Between two given dates: + * `date:2014-02/2014-04` + * `date:2014-02--2014-04` + * `date:2014-02/04` + * `date:2014-02-03/05` + * `date:2014-02-03T22:00/22:15` + * `date:2014-02-03T22:00/15` + * After a given date: + * `date:2014-03/` + * Before a given date: + * `date:/2014-03` + * For a specific duration after a given date: + * `date:2014-03/P1W` + * For a specific duration before a given date: + * `date:P1W/2014-05-25T23:59:59` + * For the past duration before now (the trailing slash is optional): + * `date:P1Y/` or `date:P1Y` (past year) + * `date:P2M/` (past two months) + * `date:P3W/` (past three weeks) + * `date:P4D/` (past four days) + * `date:PT5H/` (past five hours) + * `date:PT30M/` (past thirty minutes) + * `date:PT90S/` (past ninety seconds) + * `date:P1DT1H/` (past one day and one hour) +* by date of publication, using the same format: `pubdate:` +* by custom label ID `L:12` or multiple label IDs: `L:12,13,14` or with any label: `L:*` +* by custom label name `label:label`, `label:"my label"` or any label name from a list (*or*): `labels:"my label,my other label"` +* by several label names (*and*): `label:"my label" label:"my other label"` +* by entry (article) ID: `e:1639310674957894` or multiple entry IDs (*or*): `e:1639310674957894,1639310674957893` +* by user query (saved search) name: `search:myQuery`, `search:"My query"` or saved search ID: `S:3` + * internally, those references are replaced by the corresponding user query in the search expression + +Be careful not to enter a space between the operator and the search value. + +Some operators can be used negatively, to exclude articles, with the same syntax as above, but prefixed by a `!` or `-`: +`!f:234`, `-author:name`, `-intitle:keyword`, `-inurl:keyword`, `-#tag`, `!keyword`, `!date:2019`, `!date:P1W`, `!pubdate:P3d/`. + +It is also possible to combine keywords to create a more precise filter. +For example, you can enter multiple instances of `f:`, `author:`, `intitle:`, `inurl:`, `#`, and free-text. + +Combining several search criteria implies a logical *and*, but the keyword ` OR ` +can be used to combine several search criteria with a logical *or* instead: `author:Dupont OR author:Dupond` + +You don’t have to do anything special to combine multiple negative operators. Writing `!intitle:'thing1' !intitle:'thing2'` implies AND, see above. For more pointers on how AND and OR interact with negation, see [this GitHub comment](https://github.com/FreshRSS/FreshRSS/issues/3236#issuecomment-891219460). +Additional reading: [De Morgan's laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). + +Finally, parentheses may be used to express more complex queries, with basic negation support: + +* `(author:Alice OR intitle:hello) (author:Bob OR intitle:world)` +* `(author:Alice intitle:hello) OR (author:Bob intitle:world)` +* `!((author:Alice intitle:hello) OR (author:Bob intitle:world))` +* `(author:Alice intitle:hello) !(author:Bob intitle:world)` +* `!(S:1 OR S:2)` + +> ℹ️ If you need to search for a parenthesis, it needs to be escaped like `\(` or `\)` + +## By sorting by date + +You can change the sort order by clicking the toggle button available in the header. + +## Store your filters + +Once you came up with your perfect filter, it would be a shame if you need to recreate it every time you need to use it. + +Hopefully, there is a way to bookmark them for later use. +We call them *user queries*. +You can create as many as you want, the only limit is how they will be displayed on your screen. + +### Bookmark the current query + +Display the user queries drop-down by clicking the button next to the state buttons. +![User queries drop-down](../img/users/user.queries.drop-down.empty.png) + +Then click on the bookmark action. + +Congratulations, you’re done! + +### Using a bookmarked query + +Display the user queries drop-down by clicking the button next to the state buttons. +![User queries drop-down](../img/users/user.queries.drop-down.not.empty.png) + +Then click on the bookmarked query, the previously stored query will be applied. + +> Note that only the query is stored, not the articles. +> The results you are seeing now could be different from the results on the day you've created the query. + +--- +Read more: +* [Normal, Global and Reader view](./03_Main_view.md) +* [Refreshing the feeds](./09_refreshing_feeds.md) -- cgit v1.2.3 From 0ab130eb9c3df3227a70624bcd5e8133afb00ae5 Mon Sep 17 00:00:00 2001 From: maTh Date: Tue, 17 Jan 2023 15:39:55 +0100 Subject: Added: Mark theme as deprecated (#4807) * i18n + config * docs * deprecated marked themes * fix * fix markdown * i18n: fix link params * i18n: French * deprecated => no longer supported * i18n: German * Docs: deprecated => no longer supported * Docs: French * i18n: en-us * i18n German * isset() -> !empty() * i18n: fix German * i18n: English, delete // TODO --- app/i18n/cz/conf.php | 8 +++++++- app/i18n/de/conf.php | 8 +++++++- app/i18n/el/conf.php | 8 +++++++- app/i18n/en-us/conf.php | 8 +++++++- app/i18n/en/conf.php | 8 +++++++- app/i18n/es/conf.php | 8 +++++++- app/i18n/fr/conf.php | 8 +++++++- app/i18n/he/conf.php | 8 +++++++- app/i18n/id/conf.php | 8 +++++++- app/i18n/it/conf.php | 8 +++++++- app/i18n/ja/conf.php | 8 +++++++- app/i18n/ko/conf.php | 8 +++++++- app/i18n/nl/conf.php | 8 +++++++- app/i18n/oc/conf.php | 8 +++++++- app/i18n/pl/conf.php | 8 +++++++- app/i18n/pt-br/conf.php | 8 +++++++- app/i18n/ru/conf.php | 8 +++++++- app/i18n/sk/conf.php | 8 +++++++- app/i18n/tr/conf.php | 8 +++++++- app/i18n/zh-cn/conf.php | 8 +++++++- app/i18n/zh-tw/conf.php | 8 +++++++- app/views/configure/display.phtml | 14 ++++++++++++-- docs/en/users/05_Configuration.md | 27 +++++++++++++++++---------- docs/fr/users/05_Configuration.md | 27 +++++++++++++++++---------- p/themes/BlueLagoon/metadata.json | 3 ++- p/themes/Flat/metadata.json | 3 ++- p/themes/Screwdriver/metadata.json | 3 ++- p/themes/base-theme/frss.css | 7 ++++++- p/themes/base-theme/frss.rtl.css | 7 ++++++- 29 files changed, 211 insertions(+), 48 deletions(-) (limited to 'docs/en') diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php index 9d646be36..4411b5047 100644 --- a/app/i18n/cz/conf.php +++ b/app/i18n/cz/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Časový limit HTML5 oznámení', ), 'show_nav_buttons' => 'Zobrazit navigační tlačítka', - 'theme' => 'Motiv', + 'theme' => array( + '_' => 'Motiv', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Motiv „%s“ již není dostupný. Zvolte jiný motiv, prosím.', 'thumbnail' => array( 'label' => 'Náhled', diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php index 33604b618..8962123f4 100644 --- a/app/i18n/de/conf.php +++ b/app/i18n/de/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Zeitüberschreitung für HTML5-Benachrichtigung', ), 'show_nav_buttons' => 'Zeige Navigations-Buttons', - 'theme' => 'Erscheinungsbild', + 'theme' => array( + '_' => 'Layout', + 'deprecated' => array( + '_' => 'Veraltet', + 'description' => 'Diese Layout wird nicht mehr länger aktualisiert und wir in einer zukünftigen Version von FreshRSS entfernt sein.', + ), + ), 'theme_not_available' => 'Das Erscheinungsbild „%s“ ist nicht mehr verfügbar. Bitte ein anderes auswählen.', 'thumbnail' => array( 'label' => 'Vorschaubild', diff --git a/app/i18n/el/conf.php b/app/i18n/el/conf.php index e2629bd54..daacfe684 100644 --- a/app/i18n/el/conf.php +++ b/app/i18n/el/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 notification timeout', // TODO ), 'show_nav_buttons' => 'Show the navigation buttons', // TODO - 'theme' => 'Theme', // TODO + 'theme' => array( + '_' => 'Theme', // TODO + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'The “%s” theme is not available anymore. Please choose another theme.', // TODO 'thumbnail' => array( 'label' => 'Thumbnail', // TODO diff --git a/app/i18n/en-us/conf.php b/app/i18n/en-us/conf.php index 760cbf37f..afea0299a 100644 --- a/app/i18n/en-us/conf.php +++ b/app/i18n/en-us/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 notification timeout', // IGNORE ), 'show_nav_buttons' => 'Show the navigation buttons', // IGNORE - 'theme' => 'Theme', // IGNORE + 'theme' => array( + '_' => 'Theme', // IGNORE + 'deprecated' => array( + '_' => 'Deprecated', // IGNORE + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // IGNORE + ), + ), 'theme_not_available' => 'The “%s” theme is not available anymore. Please choose another theme.', // IGNORE 'thumbnail' => array( 'label' => 'Thumbnail', // IGNORE diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index 02f95b6a8..9899cf897 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 notification timeout', ), 'show_nav_buttons' => 'Show the navigation buttons', - 'theme' => 'Theme', + 'theme' => array( + '_' => 'Theme', + 'deprecated' => array( + '_' => 'Deprecated', + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', + ), + ), 'theme_not_available' => 'The “%s” theme is not available anymore. Please choose another theme.', 'thumbnail' => array( 'label' => 'Thumbnail', diff --git a/app/i18n/es/conf.php b/app/i18n/es/conf.php index 74d324c24..5137ff987 100755 --- a/app/i18n/es/conf.php +++ b/app/i18n/es/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Notificación de fin de espera HTML5', ), 'show_nav_buttons' => 'Mostrar los botones de navegación', - 'theme' => 'Tema', + 'theme' => array( + '_' => 'Tema', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'El tema “%s” ya no está disponible. Por favor, elija otro tema.', 'thumbnail' => array( 'label' => 'Miniatura', diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 88a51eee1..3122e3be5 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Temps d’affichage de la notification HTML5', ), 'show_nav_buttons' => 'Afficher les boutons de navigation', - 'theme' => 'Thème', + 'theme' => array( + '_' => 'Thème', + 'deprecated' => array( + '_' => 'Obsolète', + 'description' => 'Ce thème est obsolète et sera supprimé dans une future version de FreshRSS', + ), + ), 'theme_not_available' => 'Le thème %s n’est plus disponible. Veuillez choisir un autre thème.', 'thumbnail' => array( 'label' => 'Miniature', diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php index 2d0eea4b9..c4a490a2d 100644 --- a/app/i18n/he/conf.php +++ b/app/i18n/he/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 התראה פג תוקף', ), 'show_nav_buttons' => 'Show the navigation buttons', // TODO - 'theme' => 'ערכת נושא', + 'theme' => array( + '_' => 'ערכת נושא', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'The “%s” theme is not available anymore. Please choose another theme.', // TODO 'thumbnail' => array( 'label' => 'Thumbnail', // TODO diff --git a/app/i18n/id/conf.php b/app/i18n/id/conf.php index 10f649823..8b1fa8dc6 100644 --- a/app/i18n/id/conf.php +++ b/app/i18n/id/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 notification timeout', // TODO ), 'show_nav_buttons' => 'Show the navigation buttons', // TODO - 'theme' => 'Theme', // TODO + 'theme' => array( + '_' => 'Theme', // TODO + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'The “%s” theme is not available anymore. Please choose another theme.', // TODO 'thumbnail' => array( 'label' => 'Thumbnail', // TODO diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php index 5065fe7ea..6f3540322 100644 --- a/app/i18n/it/conf.php +++ b/app/i18n/it/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Notifica timeout HTML5', ), 'show_nav_buttons' => 'Mostra i pulsanti di navigazione', - 'theme' => 'Tema', + 'theme' => array( + '_' => 'Tema', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Il tema “%s” non è più disponibile. Si prega di selezionarne un altro.', 'thumbnail' => array( 'label' => 'Miniatura', diff --git a/app/i18n/ja/conf.php b/app/i18n/ja/conf.php index 1247a0ce9..4dd939760 100644 --- a/app/i18n/ja/conf.php +++ b/app/i18n/ja/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 の通知タイムアウト時間', ), 'show_nav_buttons' => 'ナビゲーションボタンを表示する', - 'theme' => 'テーマ', + 'theme' => array( + '_' => 'テーマ', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => '“%s”テーマはご利用いただけません。他のテーマをお選びください。', 'thumbnail' => array( 'label' => 'サムネイル', diff --git a/app/i18n/ko/conf.php b/app/i18n/ko/conf.php index 9ee82802e..a88fcf9e0 100644 --- a/app/i18n/ko/conf.php +++ b/app/i18n/ko/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 알림 타임아웃', ), 'show_nav_buttons' => '내비게이션 버튼 보이기', - 'theme' => '테마', + 'theme' => array( + '_' => '테마', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => '“%s” 테마는 더이상 사용할 수 없습니다. 다른 테마를 선택해 주세요.', 'thumbnail' => array( 'label' => '섬네일', diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php index 8a22f9e27..e02ca81cc 100644 --- a/app/i18n/nl/conf.php +++ b/app/i18n/nl/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 notificatie stop', ), 'show_nav_buttons' => 'Toon navigatieknoppen', - 'theme' => 'Thema', + 'theme' => array( + '_' => 'Thema', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Het „%s” thema is niet meer beschikbaar. Kies een ander thema.', 'thumbnail' => array( 'label' => 'Miniatuur', diff --git a/app/i18n/oc/conf.php b/app/i18n/oc/conf.php index 4d1e03786..4a3b483e7 100644 --- a/app/i18n/oc/conf.php +++ b/app/i18n/oc/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Temps d’afichatge de las notificacions HTML5', ), 'show_nav_buttons' => 'Mostrar los botons de navigacion', - 'theme' => 'Tèma', + 'theme' => array( + '_' => 'Tèma', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Lo tèma « %s » es pas pus disponible. Causissètz un autre tèma.', 'thumbnail' => array( 'label' => 'Vinheta', diff --git a/app/i18n/pl/conf.php b/app/i18n/pl/conf.php index f026fe128..8700a1c13 100644 --- a/app/i18n/pl/conf.php +++ b/app/i18n/pl/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Czas wyświetlania powiadomienia HTML5', ), 'show_nav_buttons' => 'Pokaż przyciski nawigacyjne', - 'theme' => 'Motyw', + 'theme' => array( + '_' => 'Motyw', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Motyw “%s” nie jest już dostępny. Wybierz inny motyw.', 'thumbnail' => array( 'label' => 'Miniaturka', diff --git a/app/i18n/pt-br/conf.php b/app/i18n/pt-br/conf.php index dc05a0fa0..f8ad55f14 100644 --- a/app/i18n/pt-br/conf.php +++ b/app/i18n/pt-br/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Notificação em HTML5 de timeout', ), 'show_nav_buttons' => 'Mostrar botões de navegação', - 'theme' => 'Tema', + 'theme' => array( + '_' => 'Tema', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'O tema “%s” não está mais disponível. Por favor escolha outro tema.', 'thumbnail' => array( 'label' => 'Miniatura', diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php index 4d65a9dcb..2c5dda544 100644 --- a/app/i18n/ru/conf.php +++ b/app/i18n/ru/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Таймаут уведомлений HTML5', ), 'show_nav_buttons' => 'Показать кнопки навигации', - 'theme' => 'Тема', + 'theme' => array( + '_' => 'Тема', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Тема “%s” больше не доступна. Пожалуйста выберите другю тему.', 'thumbnail' => array( 'label' => 'Эскиз', diff --git a/app/i18n/sk/conf.php b/app/i18n/sk/conf.php index ab68d07ca..d4714b506 100644 --- a/app/i18n/sk/conf.php +++ b/app/i18n/sk/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'Limit HTML5 oznámenia', ), 'show_nav_buttons' => 'Zobraziť tlačidlá oznámenia', - 'theme' => 'Vzhľad', + 'theme' => array( + '_' => 'Vzhľad', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => 'Vzhľad “%s” už nie je dostupný. Prosím, vyberte si iný vzhľad.', 'thumbnail' => array( 'label' => 'Miniatúra', diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php index cb72d3973..41f658879 100644 --- a/app/i18n/tr/conf.php +++ b/app/i18n/tr/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 bildirim zaman aşımı', ), 'show_nav_buttons' => 'Gezinti düğmelerini göster', - 'theme' => 'Tema', + 'theme' => array( + '_' => 'Tema', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => '“%s” teması şuan uygun değilç Lütfen başka bir tema seçin.', 'thumbnail' => array( 'label' => 'Önizleme', diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php index d558c025e..0be182cfb 100644 --- a/app/i18n/zh-cn/conf.php +++ b/app/i18n/zh-cn/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 通知超时时间', ), 'show_nav_buttons' => '显示导航按钮', - 'theme' => '主题', + 'theme' => array( + '_' => '主题', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => '“%s” 主题不再可用,请选择其他主题。', 'thumbnail' => array( 'label' => '缩略图', diff --git a/app/i18n/zh-tw/conf.php b/app/i18n/zh-tw/conf.php index 3001f64c5..34439c01b 100644 --- a/app/i18n/zh-tw/conf.php +++ b/app/i18n/zh-tw/conf.php @@ -49,7 +49,13 @@ return array( 'timeout' => 'HTML5 通知超時時間', ), 'show_nav_buttons' => '顯示導航按鈕', - 'theme' => '主題', + 'theme' => array( + '_' => '主題', + 'deprecated' => array( + '_' => 'Deprecated', // TODO + 'description' => 'This theme is no longer supported and will be not available anymore in a future release of FreshRSS', // TODO + ), + ), 'theme_not_available' => '“%s” 主題不再可用,請選擇其他主題。', 'thumbnail' => array( 'label' => '縮圖', diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 8d23f6ef0..986d7dd17 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -71,8 +71,18 @@
-
-
+
+ + : + + +
+
+ +
+ + +
diff --git a/docs/en/users/05_Configuration.md b/docs/en/users/05_Configuration.md index 9ad6a58ca..1ce0e0a0d 100644 --- a/docs/en/users/05_Configuration.md +++ b/docs/en/users/05_Configuration.md @@ -13,16 +13,23 @@ Available languages are: cz, de, en, es, fr, he, it, ko, nl, oc, pt-br, ru, tr, ## Theme -There’s no accounting for tastes, which is why FreshRSS offers eight official themes: - -* *Blue Lagoon* by **Mister aiR** -* *Dark* by **AD** -* *Flat design* by **Marien Fressinaud** -* *Origine* by **Marien Fressinaud** -* *Origine-compact* by **Kevin Papst** -* *Pafat* by **Plopoyop** -* *Screwdriver* by **Mister aiR** -* *Swage* by **Patrick Crandol** +There’s no accounting for tastes, which is why FreshRSS offers 13 official themes: + +| Theme | designed by | Notes | +|:--------------|:-------------------------------------------------------|:--------------------------------------------------------------| +| Alternative Dark | Ghost | | +| Ansum | Thomas Guesnon | | +| Blue Lagoon |Mister aiR | No longer supported. Will be removed with FreshRSS V1.22.0 | +| Dark | AD | | +| Dark pink | Miicat_47 | | +| Flat design | Marien Fressinaud | No longer supported. Will be removed with FreshRSS V1.22.0 | +| Mapco | Thomas Guesnon | | +| Nord theme | joelchrono12 | | +| Origine | Marien Fressinaud | (default theme) | +| Origine-compact | Kevin Papst | | +| Pafat | Plopoyop | | +| Screwdriver | Mister aiR | No longer supported. Will be removed with FreshRSS V1.22.0 | +| Swage | Patrick Crandol | | If you can’t find any themes you like, it’s always possible to [create your own](../developers/04_Frontend/02_Design.md). diff --git a/docs/fr/users/05_Configuration.md b/docs/fr/users/05_Configuration.md index 88478a280..c64572d01 100644 --- a/docs/fr/users/05_Configuration.md +++ b/docs/fr/users/05_Configuration.md @@ -21,16 +21,23 @@ pt-br, ru, tr, zh-cn. ## Thème Les goûts et les couleurs, ça ne se discute pas. C’est pourquoi FreshRSS -propose huit thèmes officiels : - -* *Blue Lagoon* par **Mister aiR** -* *Dark* par **AD** -* *Flat design* par **Marien Fressinaud** -* *Origine* par **Marien Fressinaud** -* *Origine-compact* par **Kevin Papst** -* *Pafat* par **Plopoyop** -* *Screwdriver* par **Mister aiR** -* *Swage* par **Patrick Crandol** +propose 13 thèmes officiels : + +| Thème | Auteur | Notes | +|:--------------|:-------------------------------------------------------|:--------------------------------------------------------------| +| Alternative Dark | Ghost | | +| Ansum | Thomas Guesnon | | +| Blue Lagoon |Mister aiR | N'est plus pris en charge. Sera supprimé avec FreshRSS V1.22.0 | +| Dark | AD | | +| Dark pink | Miicat_47 | | +| Flat design | Marien Fressinaud | N'est plus pris en charge. Sera supprimé avec FreshRSS V1.22.0 | +| Mapco | Thomas Guesnon | | +| Nord theme | joelchrono12 | | +| Origine | Marien Fressinaud | (default theme) | +| Origine-compact | Kevin Papst | | +| Pafat | Plopoyop | | +| Screwdriver | Mister aiR | N'est plus pris en charge. Sera supprimé avec FreshRSS V1.22.0 | +| Swage | Patrick Crandol | | Si aucun de ceux proposés ne convient, il est toujours possible de [créer son propre thème](../developers/04_Frontend/02_Design.md). diff --git a/p/themes/BlueLagoon/metadata.json b/p/themes/BlueLagoon/metadata.json index 7822d7346..37750c631 100644 --- a/p/themes/BlueLagoon/metadata.json +++ b/p/themes/BlueLagoon/metadata.json @@ -3,5 +3,6 @@ "author": "Mister aiR", "description": "C’est un cocktail (bis)! C’est la version plus fresh de Screwdriver. C’est… c’est… un thème pour l’agrégateur de flux RSS FreshRSS. En toute modestie, ce thème tue du Nyan Cat.", "version": 1.0, - "files": ["_frss.css","BlueLagoon.css"] + "files": ["_frss.css","BlueLagoon.css"], + "deprecated": true } diff --git a/p/themes/Flat/metadata.json b/p/themes/Flat/metadata.json index 27a83fe83..bd7ce6157 100644 --- a/p/themes/Flat/metadata.json +++ b/p/themes/Flat/metadata.json @@ -3,5 +3,6 @@ "author": "Marien Fressinaud", "description": "Thème plat pour FreshRSS", "version": 0.2, - "files": ["_frss.css", "flat.css"] + "files": ["_frss.css", "flat.css"], + "deprecated": true } diff --git a/p/themes/Screwdriver/metadata.json b/p/themes/Screwdriver/metadata.json index 08654e51d..8da73f80c 100644 --- a/p/themes/Screwdriver/metadata.json +++ b/p/themes/Screwdriver/metadata.json @@ -3,5 +3,6 @@ "author": "Mister aiR", "description": "C’est un cocktail ! C’est chaud mais « fresh » à la fois. Ce thème tue du chaton.", "version": 1.1, - "files": ["_frss.css","screwdriver.css"] + "files": ["_frss.css","screwdriver.css"], + "deprecated" : true } diff --git a/p/themes/base-theme/frss.css b/p/themes/base-theme/frss.css index 8bd4a7e99..a24d7c32c 100644 --- a/p/themes/base-theme/frss.css +++ b/p/themes/base-theme/frss.css @@ -1809,11 +1809,16 @@ input:checked + .slide-container .properties { .item.share.error a::after, .category .title.error::before, -.item.feed.error .item-title::before { +.item.feed.error .item-title::before, +.properties .error::before { content: " ⚠ "; color: var(--frss-font-color-error); } +.deprecated { + font-weight: bold; +} + .feed.item.error.active .item-title::before { color: var(--frss-font-color-light); } diff --git a/p/themes/base-theme/frss.rtl.css b/p/themes/base-theme/frss.rtl.css index 9e5221126..4a8782c7e 100644 --- a/p/themes/base-theme/frss.rtl.css +++ b/p/themes/base-theme/frss.rtl.css @@ -1809,11 +1809,16 @@ input:checked + .slide-container .properties { .item.share.error a::after, .category .title.error::before, -.item.feed.error .item-title::before { +.item.feed.error .item-title::before, +.properties .error::before { content: " ⚠ "; color: var(--frss-font-color-error); } +.deprecated { + font-weight: bold; +} + .feed.item.error.active .item-title::before { color: var(--frss-font-color-light); } -- cgit v1.2.3 From 216e39c3cc43061686981b96328796765d264d29 Mon Sep 17 00:00:00 2001 From: maTh Date: Tue, 17 Jan 2023 23:41:49 +0100 Subject: Docs: Explain the "Do not automatically refresh more often than" (#5017) * reordering, config, TOC * fix markdownlint * fix --- docs/en/users/09_refreshing_feeds.md | 67 ++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 18 deletions(-) (limited to 'docs/en') diff --git a/docs/en/users/09_refreshing_feeds.md b/docs/en/users/09_refreshing_feeds.md index ec20c7d62..6d9c2af55 100644 --- a/docs/en/users/09_refreshing_feeds.md +++ b/docs/en/users/09_refreshing_feeds.md @@ -1,6 +1,39 @@ # Refreshing feeds -To take full advantage of FreshRSS, it needs to retrieve new items from the feeds you have subscribed to. There are several ways to do this. +To take full advantage of FreshRSS, it needs to retrieve new items from the feeds you have subscribed to. There are several ways to do this: + +- [Manual update](#manual-update) + - [Complete update](#complete-update) + - [Partial update](#partial-update) +- [Automatic update with cron](#automatic-update-with-cron) +- [Online cron](#online-cron) + - [For Form Authentication](#for-form-authentication) + - [For HTTP authentication](#for-http-authentication) + - [For No authentication None](#for-no-authentication-none) +- [Feed configuration of “Do not automatically refresh more often than”](#feed-configuration-of-do-not-automatically-refresh-more-often-than) + - [Background](#background) + - [Default value](#default-value) + - [Individual feed configuration](#individual-feed-configuration) + +## Manual update + +If you can’t or don’t want to use the automatic method, you can update manually. There are two methods for updating all or some of the feeds. + +### Complete update + +This update occurs on all feeds. To trigger it, simply click on the update link in the navigation menu. + +![Navigation menu](../img/users/refresh.1.png) + +When the update starts, a progress bar appears and changes while feeds are processed. + +![Progress bar](../img/users/refresh.5.png) + +### Partial update + +This update occurs on the selected feed only. To trigger it, simply click on the update link in the feed menu. + +![Feed menu](../img/users/refresh.2.png) ## Automatic update with cron @@ -25,19 +58,19 @@ To do so, you need to create a scheduled task, which need to call a specific URL Special parameters to configure the script - all parameters can be combined: -* Parameter "force" +- Parameter "force" If *force* is set to 1 all feeds will be refreshed at once. -* Parameter "ajax" +- Parameter "ajax" Only a status site is returned and not a complete website. Example: "OK" -* Parameter "maxFeeds" +- Parameter "maxFeeds" If *maxFeeds* is set the configured amount of feeds is refreshed at once. The default setting is "10". -* Parameter "token" +- Parameter "token" Security parameter to prevent unauthorized refreshes. For detailed Documentation see "Form authentication". @@ -77,27 +110,25 @@ If your FreshRSS instance uses no authentication (public instance, default user) -## Manual update +## Feed configuration of “Do not automatically refresh more often than” -If you can’t or don’t want to use the automatic method, you can update manually. There are two methods for updating all or some of the feeds. +### Background -### Complete update +FreshRSS does not, by design, supports pull refreshes at frequencies higher than once every 15 minutes. But FreshRSS supports instant push (WebSub). -This update occurs on all feeds. To trigger it, simply click on the update link in the navigation menu. +FreshRSS is part of an RSS ecosystem. A typical reaction that we have seen from several servers is to simply ban by, IP, user-agent, or to remove their RSS feed altogether. Bad user behaviours affect the larger community. -![Navigation menu](../img/users/refresh.1.png) +### Default value -When the update starts, a progress bar appears and changes while feeds are processed. +The default value of “Do not automatically refresh more often than” is set in Configuration -> Archiving. -![Progress bar](../img/users/refresh.5.png) +The lowest global/default purposely cannot be set faster than every 20 minutes, to avoid wasting resources and make sure the RSS ecosystem remains sane. -### Partial update +### Individual feed configuration -This update occurs on the selected feed only. To trigger it, simply click on the update link in the feed menu. - -![Feed menu](../img/users/refresh.2.png) +Under the settings for individual feeds, you can go down to 15min. --- Read more: -* [Normal, Global and Reader view](./03_Main_view.md) -* [Filter the feeds and search](./10_filter.md) +- [Normal, Global and Reader view](./03_Main_view.md) +- [Filter the feeds and search](./10_filter.md) -- cgit v1.2.3 From 2303b29e68d16fbf0a173ab2b4b0ac736041905c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 28 Jan 2023 23:15:28 +0100 Subject: Document cleaning the logs for passwords (#5050) Follow up of https://github.com/FreshRSS/FreshRSS/pull/5001 --- docs/en/admins/10_ServerConfig.md | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs/en') diff --git a/docs/en/admins/10_ServerConfig.md b/docs/en/admins/10_ServerConfig.md index 6c5823a2d..87bd74d09 100644 --- a/docs/en/admins/10_ServerConfig.md +++ b/docs/en/admins/10_ServerConfig.md @@ -1,8 +1,13 @@ # Apache/Nginx Configuration Files +> ℹ️ For improved security, remove sensitive information in the Web server logs by using our [`sensitive-log.sh` script](https://github.com/FreshRSS/FreshRSS/blob/edge/cli/sensitive-log.sh), +on the model of our [reference Apache configuration](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/FreshRSS.Apache.conf) used for our official Docker images +(see [`CustomLog`](https://httpd.apache.org/docs/current/mod/mod_log_config.html#customlog)). + ## Apache configuration This is an example Apache virtual hosts configuration file. It covers HTTP and HTTPS configuration. +For more details, check our [reference Apache configuration](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/FreshRSS.Apache.conf) used for our official Docker images. ```apache @@ -24,6 +29,7 @@ This is an example Apache virtual hosts configuration file. It covers HTTP and H ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log + # Consider piping the logs for cleaning passwords; cf. comment higher up. CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined AllowEncodedSlashes On -- cgit v1.2.3 From de2077b56388c5196d5c1ddcbbd4a141ea8cf67b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 6 Feb 2023 14:11:41 +0100 Subject: Increase max HTTP timeout (#5074) * Increase maximum HTTP request timeout from 2 minutes to 15 minutes; * Reason: I have some RSS Bridge generating feeds, which can take several minutes. * Increase default HTTP request timeout from 15 to 20s. * Reason: I regularly observe feeds, which are slow to answer. --- app/views/helpers/feed/update.phtml | 2 +- app/views/subscription/add.phtml | 2 +- config.default.php | 2 +- docs/en/users/04_Subscriptions.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/en') diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 8dbba0ab0..5b958451d 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -602,7 +602,7 @@
- +
diff --git a/app/views/subscription/add.phtml b/app/views/subscription/add.phtml index 212574002..7fa59e751 100644 --- a/app/views/subscription/add.phtml +++ b/app/views/subscription/add.phtml @@ -237,7 +237,7 @@
- +
diff --git a/config.default.php b/config.default.php index 37eb4d6d5..d0873d55d 100644 --- a/config.default.php +++ b/config.default.php @@ -103,7 +103,7 @@ return array( 'cache_duration' => 800, # SimplePie HTTP request timeout in seconds. - 'timeout' => 15, + 'timeout' => 20, # If a user has not used FreshRSS for more than x seconds, # then its feeds are not refreshed anymore. diff --git a/docs/en/users/04_Subscriptions.md b/docs/en/users/04_Subscriptions.md index a6b54ffe8..7b0a488f0 100644 --- a/docs/en/users/04_Subscriptions.md +++ b/docs/en/users/04_Subscriptions.md @@ -5,7 +5,7 @@ 3. Paste the URL in the “Feed URL” field. 4. (optional): You can select the category for your feed. By default, it will be in “Uncategorized”. 5. (optional): If the subscription requires credentials, you can enter them in the "HTTP username" and "HTTP password" fields. -6. (optional): You can set a timeout for the feed request if the feed requires it. +6. (optional): You can set a timeout for the feed request. 7. (optional): You can choose to ignore SSL certificate errors (such as with self-signed certificates) by setting "Verify SSL security" to "No". This is not recommended, and it is better to either add the root certificate to the FreshRSS server or to fix the SSL certificate problems on the feed hosting server. ## Subscription management -- cgit v1.2.3 From e899e4edd97c296a29b2a8da2c2e3b598622c36e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 6 Feb 2023 15:42:53 +0100 Subject: More robust application of access permissions (#5062) * More robust application of access permissions We were in particular missing directory traversal `+X` in our current recommendations. Extracted to own shell script so it can easily be invoked. Update access permissions in Docker to account to be more robust. #fix https://github.com/FreshRSS/FreshRSS/discussions/5037 * Minor simplification * Restrict mkdir permissions Default mkdir permissions are 0777, which is not good for security, so downgrade to 0770. --- Docker/entrypoint.sh | 11 +++++------ README.fr.md | 4 ++-- app/Controllers/userController.php | 2 +- app/Models/Feed.php | 4 ++-- cli/README.md | 4 +--- cli/_cli.php | 2 +- cli/access-permissions.sh | 19 +++++++++++++++++++ cli/i18n/I18nFile.php | 2 +- docs/en/admins/06_LinuxInstall.md | 9 +-------- docs/en/admins/07_LinuxUpdate.md | 4 ++-- lib/Minz/Migrator.php | 2 +- 11 files changed, 36 insertions(+), 27 deletions(-) create mode 100755 cli/access-permissions.sh (limited to 'docs/en') diff --git a/Docker/entrypoint.sh b/Docker/entrypoint.sh index 018946397..cbc2443d6 100755 --- a/Docker/entrypoint.sh +++ b/Docker/entrypoint.sh @@ -7,8 +7,6 @@ find /etc/php*/ -type f -name php.ini -exec sed -r -i "\\#^;?date.timezone#s#^.* find /etc/php*/ -type f -name php.ini -exec sed -r -i "\\#^;?post_max_size#s#^.*#post_max_size = 32M#" {} \; find /etc/php*/ -type f -name php.ini -exec sed -r -i "\\#^;?upload_max_filesize#s#^.*#upload_max_filesize = 32M#" {} \; -php -f ./cli/prepare.php >/dev/null - if [ -n "$LISTEN" ]; then find /etc/apache2/ -type f -name FreshRSS.Apache.conf -exec sed -r -i "\\#^Listen#s#^.*#Listen $LISTEN#" {} \; fi @@ -24,6 +22,10 @@ if [ -n "$CRON_MIN" ]; then -r "s#^[^ ]+ #$CRON_MIN #" | crontab - fi +./cli/access-permissions.sh + +php -f ./cli/prepare.php >/dev/null + if [ -n "$FRESHRSS_INSTALL" ]; then # shellcheck disable=SC2046 php -f ./cli/do-install.php -- \ @@ -57,9 +59,6 @@ if [ -n "$FRESHRSS_USER" ]; then fi fi -chown -R :www-data . -chmod -R g+r . -chmod -R g+w ./data/ -chmod g+x ./extensions/ +./cli/access-permissions.sh exec "$@" diff --git a/README.fr.md b/README.fr.md index 99b5a1a2c..221385ab5 100644 --- a/README.fr.md +++ b/README.fr.md @@ -113,7 +113,7 @@ cd FreshRSS sudo git checkout $(git describe --tags --abbrev=0) # Mettre les droits d’accès pour le serveur Web -sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ +sudo cli/access-permissions.sh # Si vous souhaitez permettre les mises à jour par l’interface Web sudo chmod -R g+w . @@ -126,7 +126,7 @@ sudo ln -s /usr/share/FreshRSS/p /var/www/html/FreshRSS # Mettre à jour FreshRSS vers une nouvelle version par git cd /usr/share/FreshRSS sudo git pull -sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ +sudo cli/access-permissions.sh ``` Voir la [documentation de la ligne de commande](cli/README.md) pour plus de détails. diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 55b4ca7cb..ac8f3be82 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -242,7 +242,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { } if ($ok) { if (!is_dir($homeDir)) { - mkdir($homeDir); + mkdir($homeDir, 0770, true); } $ok &= (file_put_contents($configPath, "salt); $hubJson = array( 'hub' => $this->hubUrl, 'key' => $key, ); file_put_contents($hubFilename, json_encode($hubJson)); - @mkdir(PSHB_PATH . '/keys/'); + @mkdir(PSHB_PATH . '/keys/', 0770, true); file_put_contents(PSHB_PATH . '/keys/' . $key . '.txt', $this->selfUrl); $text = 'WebSub prepared for ' . $this->url; Minz_Log::debug($text); diff --git a/cli/README.md b/cli/README.md index e290cc267..cb43b7340 100644 --- a/cli/README.md +++ b/cli/README.md @@ -18,9 +18,7 @@ In any case, when you are done with a series of commands, you should re-apply th ```sh cd /usr/share/FreshRSS -sudo chown -R :www-data . -sudo chmod -R g+r . -sudo chmod -R g+w ./data/ +sudo cli/access-permissions.sh ``` diff --git a/cli/_cli.php b/cli/_cli.php index 10a92385a..0d2c8695f 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -44,7 +44,7 @@ function cliInitUser($username) { function accessRights() { echo 'ℹ️ Remember to re-apply the appropriate access rights, such as:', - "\t", 'sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/', "\n"; + "\t", 'sudo cli/access-permissions.sh', "\n"; } function done($ok = true) { diff --git a/cli/access-permissions.sh b/cli/access-permissions.sh new file mode 100755 index 000000000..c13130a4b --- /dev/null +++ b/cli/access-permissions.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Apply access permissions + +if [ ! -f './constants.php' ] || [ ! -d './cli/' ]; then + echo >&2 '⛔ It does not look like a FreshRSS directory; exiting!' + exit 2 +fi + +if [ "$(id -u)" -ne 0 ]; then + echo >&2 '⛔ Applying access permissions require running as root or sudo!' + exit 3 +fi + +# Based on group access +chown -R :www-data . +# Read files, and directory traversal +chmod -R g+rX . +# Write access +chmod -R g+w ./data/ diff --git a/cli/i18n/I18nFile.php b/cli/i18n/I18nFile.php index fca31d662..12a04c6a2 100644 --- a/cli/i18n/I18nFile.php +++ b/cli/i18n/I18nFile.php @@ -27,7 +27,7 @@ class I18nFile { foreach ($i18n as $language => $file) { $dir = I18N_PATH . DIRECTORY_SEPARATOR . $language; if (!file_exists($dir)) { - mkdir($dir); + mkdir($dir, 0770, true); } foreach ($file as $name => $content) { $filename = $dir . DIRECTORY_SEPARATOR . $name; diff --git a/docs/en/admins/06_LinuxInstall.md b/docs/en/admins/06_LinuxInstall.md index e92fc3247..1af041efe 100644 --- a/docs/en/admins/06_LinuxInstall.md +++ b/docs/en/admins/06_LinuxInstall.md @@ -81,14 +81,7 @@ Change to the new FreshRSS directory, and set the permissions so that your Web s ```sh cd FreshRSS -chown -R :www-data . -sudo chmod -R g+r . -``` - -We’ll also need to allow the data folder to be written to, like so: - -```sh -chmod -R g+w ./data/ +sudo cli/access-permissions.sh ``` Optional: If you would like to allow updates from the Web interface, set write permissions diff --git a/docs/en/admins/07_LinuxUpdate.md b/docs/en/admins/07_LinuxUpdate.md index 834dfaaef..27e8ef451 100644 --- a/docs/en/admins/07_LinuxUpdate.md +++ b/docs/en/admins/07_LinuxUpdate.md @@ -64,7 +64,7 @@ If your local user doesn’t have write access to the FreshRSS folder, use a sud 6. Re-set correct permissions so that your web server can access the files ```sh - chown -R :www-data . && chmod -R g+r . && chmod -R g+w ./data/ + cli/access-permissions.sh ``` ## Using the Zip archive @@ -91,7 +91,7 @@ If your local user doesn’t have write access to the FreshRSS folder, use a sud 5. Re-set permissions ```sh - chown -R :www-data . && chmod -R g+r . && chmod -R g+w ./data/ + cli/access-permissions.sh ``` 6. Clean up the FreshRSS directory by deleting the downloaded zip and the temporary directory diff --git a/lib/Minz/Migrator.php b/lib/Minz/Migrator.php index 0f28237c5..ef89a3b55 100644 --- a/lib/Minz/Migrator.php +++ b/lib/Minz/Migrator.php @@ -55,7 +55,7 @@ class Minz_Migrator } $lock_path = $applied_migrations_path . '.lock'; - if (!@mkdir($lock_path)) { + if (!@mkdir($lock_path, 0770, true)) { // Someone is probably already executing the migrations (the folder // already exists). // We should probably return something else, but we don't want the -- cgit v1.2.3 From 05ae1b0d2684cea4eda664c5ea1a995cb9f0c4b9 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 9 Feb 2023 13:57:20 +0100 Subject: XML+XPath (#5076) * XML+XPath #fix https://github.com/FreshRSS/FreshRSS/issues/5075 Implementation allowing to take an XML document as input using an XML parser (instead of an HTML parser for HTML+XPath) * Remove noise from another PR * Better MIME for XML * And add glob *.xml for cache cleaning * Minor syntax * Add glob json for clean cache --- app/Controllers/feedController.php | 14 ++++++++++---- app/Controllers/subscriptionController.php | 2 +- app/Models/Feed.php | 29 ++++++++++++++++++++++++----- app/Services/ExportService.php | 1 + app/Services/ImportService.php | 5 ++++- app/i18n/cz/sub.php | 1 + app/i18n/de/sub.php | 1 + app/i18n/el/sub.php | 1 + app/i18n/en-us/sub.php | 1 + app/i18n/en/sub.php | 1 + app/i18n/es/sub.php | 1 + app/i18n/fr/sub.php | 1 + app/i18n/he/sub.php | 1 + app/i18n/id/sub.php | 1 + app/i18n/it/sub.php | 1 + app/i18n/ja/sub.php | 1 + app/i18n/ko/sub.php | 1 + app/i18n/nl/sub.php | 1 + app/i18n/oc/sub.php | 1 + app/i18n/pl/sub.php | 1 + app/i18n/pt-br/sub.php | 1 + app/i18n/ru/sub.php | 1 + app/i18n/sk/sub.php | 1 + app/i18n/tr/sub.php | 1 + app/i18n/zh-cn/sub.php | 1 + app/i18n/zh-tw/sub.php | 1 + app/views/helpers/export/opml.phtml | 11 +++++++++-- app/views/helpers/feed/update.phtml | 5 +++-- app/views/subscription/add.phtml | 1 + docs/en/developers/OPML.md | 4 +++- lib/lib_rss.php | 14 ++++++++++++-- p/scripts/feed.js | 11 +++++++++-- 32 files changed, 98 insertions(+), 20 deletions(-) (limited to 'docs/en') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 2bef85f0e..84f38fe5e 100644 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -81,6 +81,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $feed->load(true); //Throws FreshRSS_Feed_Exception, Minz_FileNotExistException break; case FreshRSS_Feed::KIND_HTML_XPATH: + case FreshRSS_Feed::KIND_XML_XPATH: $feed->_website($url); break; } @@ -201,8 +202,8 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $timeout = intval(Minz_Request::param('timeout', 0)); $attributes['timeout'] = $timeout > 0 ? $timeout : null; - $feed_kind = Minz_Request::param('feed_kind', FreshRSS_Feed::KIND_RSS); - if ($feed_kind == FreshRSS_Feed::KIND_HTML_XPATH) { + $feed_kind = (int)Minz_Request::param('feed_kind', FreshRSS_Feed::KIND_RSS); + if ($feed_kind === FreshRSS_Feed::KIND_HTML_XPATH || $feed_kind === FreshRSS_Feed::KIND_XML_XPATH) { $xPathSettings = []; if (Minz_Request::param('xPathFeedTitle', '') != '') $xPathSettings['feedTitle'] = Minz_Request::param('xPathFeedTitle', '', true); if (Minz_Request::param('xPathItem', '') != '') $xPathSettings['item'] = Minz_Request::param('xPathItem', '', true); @@ -385,10 +386,15 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { if ($simplePiePush) { $simplePie = $simplePiePush; //Used by WebSub } elseif ($feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH) { - $simplePie = $feed->loadHtmlXpath(false, $isNewFeed); - if ($simplePie == null) { + $simplePie = $feed->loadHtmlXpath(); + if ($simplePie === null) { throw new FreshRSS_Feed_Exception('HTML+XPath Web scraping failed for [' . $feed->url(false) . ']'); } + } elseif ($feed->kind() === FreshRSS_Feed::KIND_XML_XPATH) { + $simplePie = $feed->loadHtmlXpath(); + if ($simplePie === null) { + throw new FreshRSS_Feed_Exception('XML+XPath parsing failed for [' . $feed->url(false) . ']'); + } } else { $simplePie = $feed->load(false, $isNewFeed); } diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index b2ee046d9..f0355a82a 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -203,7 +203,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController { $feed->_filtersAction('read', preg_split('/[\n\r]+/', Minz_Request::param('filteractions_read', ''))); $feed->_kind(intval(Minz_Request::param('feed_kind', FreshRSS_Feed::KIND_RSS))); - if ($feed->kind() == FreshRSS_Feed::KIND_HTML_XPATH) { + if ($feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH || $feed->kind() === FreshRSS_Feed::KIND_XML_XPATH) { $xPathSettings = []; if (Minz_Request::param('xPathItem', '') != '') $xPathSettings['item'] = Minz_Request::param('xPathItem', '', true); if (Minz_Request::param('xPathItemTitle', '') != '') $xPathSettings['itemTitle'] = Minz_Request::param('xPathItemTitle', '', true); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index f7ff76768..7c46199a5 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -17,6 +17,11 @@ class FreshRSS_Feed extends Minz_Model { * @var int */ const KIND_HTML_XPATH = 10; + /** + * Normal XML with XPath scraping + * @var int + */ + const KIND_XML_XPATH = 15; /** * Normal JSON with XPath scraping * @var int @@ -586,7 +591,7 @@ class FreshRSS_Feed extends Minz_Model { /** * @return SimplePie|null */ - public function loadHtmlXpath(bool $loadDetails = false, bool $noCache = false) { + public function loadHtmlXpath() { if ($this->url == '') { return null; } @@ -614,8 +619,9 @@ class FreshRSS_Feed extends Minz_Model { return null; } - $cachePath = FreshRSS_Feed::cacheFilename($feedSourceUrl, $this->attributes(), FreshRSS_Feed::KIND_HTML_XPATH); - $html = httpGet($feedSourceUrl, $cachePath, 'html', $this->attributes()); + $cachePath = FreshRSS_Feed::cacheFilename($feedSourceUrl, $this->attributes(), $this->kind()); + $html = httpGet($feedSourceUrl, $cachePath, + $this->kind() === FreshRSS_Feed::KIND_XML_XPATH ? 'xml' : 'html', $this->attributes()); if (strlen($html) <= 0) { return null; } @@ -630,7 +636,18 @@ class FreshRSS_Feed extends Minz_Model { $doc = new DOMDocument(); $doc->recover = true; $doc->strictErrorChecking = false; - $doc->loadHTML($html, LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING); + + switch ($this->kind()) { + case FreshRSS_Feed::KIND_HTML_XPATH: + $doc->loadHTML($html, LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING); + break; + case FreshRSS_Feed::KIND_XML_XPATH: + $doc->loadXML($html, LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING); + break; + default: + return null; + } + $xpath = new DOMXPath($doc); $view->rss_title = $xPathFeedTitle == '' ? $this->name() : htmlspecialchars(@$xpath->evaluate('normalize-space(' . $xPathFeedTitle . ')'), ENT_COMPAT, 'UTF-8'); @@ -776,8 +793,10 @@ class FreshRSS_Feed extends Minz_Model { public static function cacheFilename(string $url, array $attributes, int $kind = FreshRSS_Feed::KIND_RSS): string { $simplePie = customSimplePie($attributes); $filename = $simplePie->get_cache_filename($url); - if ($kind == FreshRSS_Feed::KIND_HTML_XPATH) { + if ($kind === FreshRSS_Feed::KIND_HTML_XPATH) { return CACHE_PATH . '/' . $filename . '.html'; + } elseif ($kind === FreshRSS_Feed::KIND_XML_XPATH) { + return CACHE_PATH . '/' . $filename . '.xml'; } else { return CACHE_PATH . '/' . $filename . '.spc'; } diff --git a/app/Services/ExportService.php b/app/Services/ExportService.php index 2f35666a8..6b0a3f178 100644 --- a/app/Services/ExportService.php +++ b/app/Services/ExportService.php @@ -21,6 +21,7 @@ class FreshRSS_Export_Service { const FRSS_NAMESPACE = 'https://freshrss.org/opml'; const TYPE_HTML_XPATH = 'HTML+XPath'; + const TYPE_XML_XPATH = 'XML+XPath'; const TYPE_RSS_ATOM = 'rss'; /** diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 68aa6f741..55aa28679 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -160,10 +160,13 @@ class FreshRSS_Import_Service { $feed->_website($website); $feed->_description($description); - switch ($feed_elt['type'] ?? '') { + switch (strtolower($feed_elt['type'] ?? '')) { case strtolower(FreshRSS_Export_Service::TYPE_HTML_XPATH): $feed->_kind(FreshRSS_Feed::KIND_HTML_XPATH); break; + case strtolower(FreshRSS_Export_Service::TYPE_XML_XPATH): + $feed->_kind(FreshRSS_Feed::KIND_XML_XPATH); + break; case strtolower(FreshRSS_Export_Service::TYPE_RSS_ATOM): default: $feed->_kind(FreshRSS_Feed::KIND_RSS); diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php index a11a9359d..3d08c315b 100644 --- a/app/i18n/cz/sub.php +++ b/app/i18n/cz/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath pro:', ), 'rss' => 'RSS / Atom (výchozí)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Vymazat mezipaměť', diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php index 580f7d348..b265c1b98 100644 --- a/app/i18n/de/sub.php +++ b/app/i18n/de/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath für:', ), 'rss' => 'RSS / Atom (Standard)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Zwischenspeicher leeren', diff --git a/app/i18n/el/sub.php b/app/i18n/el/sub.php index 424fafc7b..aae9ae412 100644 --- a/app/i18n/el/sub.php +++ b/app/i18n/el/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath for:', // TODO ), 'rss' => 'RSS / Atom (default)', // TODO + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Clear cache', // TODO diff --git a/app/i18n/en-us/sub.php b/app/i18n/en-us/sub.php index a6b311084..92d75b81e 100644 --- a/app/i18n/en-us/sub.php +++ b/app/i18n/en-us/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath for:', // IGNORE ), 'rss' => 'RSS / Atom (default)', // IGNORE + 'xml_xpath' => 'XML + XPath', // IGNORE ), 'maintenance' => array( 'clear_cache' => 'Clear cache', // IGNORE diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index c7e100c25..04caaff05 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath for:', ), 'rss' => 'RSS / Atom (default)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Clear cache', diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php index 52d681067..4fd2fa393 100644 --- a/app/i18n/es/sub.php +++ b/app/i18n/es/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath para:', ), 'rss' => 'RSS / Atom (por defecto)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Borrar caché', diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php index f9df0dbcc..be6dc094d 100644 --- a/app/i18n/fr/sub.php +++ b/app/i18n/fr/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath pour :', ), 'rss' => 'RSS / Atom (par défaut)', + 'xml_xpath' => 'XML + XPath', // IGNORE ), 'maintenance' => array( 'clear_cache' => 'Vider le cache', diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php index 25552ffa1..bae5f5177 100644 --- a/app/i18n/he/sub.php +++ b/app/i18n/he/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath for:', // TODO ), 'rss' => 'RSS / Atom (default)', // TODO + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Clear cache', // TODO diff --git a/app/i18n/id/sub.php b/app/i18n/id/sub.php index 7fdf5c024..3f9a4916a 100644 --- a/app/i18n/id/sub.php +++ b/app/i18n/id/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath for:', // TODO ), 'rss' => 'RSS / Atom (default)', // TODO + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Clear cache', // TODO diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php index 8614caca7..7ab83cf07 100644 --- a/app/i18n/it/sub.php +++ b/app/i18n/it/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath per:', ), 'rss' => 'RSS / Atom (predefinito)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Svuota cache', diff --git a/app/i18n/ja/sub.php b/app/i18n/ja/sub.php index 80548c025..2425b21f3 100644 --- a/app/i18n/ja/sub.php +++ b/app/i18n/ja/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPathは:', ), 'rss' => 'RSS / Atom (標準)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'キャッシュのクリア', diff --git a/app/i18n/ko/sub.php b/app/i18n/ko/sub.php index e0ef5990b..f376247d5 100644 --- a/app/i18n/ko/sub.php +++ b/app/i18n/ko/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => '다음의 XPath:', ), 'rss' => 'RSS / Atom (기본값)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => '캐쉬 지우기', diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index 0fa767171..631da9477 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath voor:', ), 'rss' => 'RSS / Atom (standaard)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Cache leegmaken', diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php index 92a73057c..008b4964d 100644 --- a/app/i18n/oc/sub.php +++ b/app/i18n/oc/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath per :', ), 'rss' => 'RSS / Atom (defaut)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Escafar lo cache', diff --git a/app/i18n/pl/sub.php b/app/i18n/pl/sub.php index b6121fcb7..565401982 100644 --- a/app/i18n/pl/sub.php +++ b/app/i18n/pl/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath dla:', ), 'rss' => 'RSS / Atom (domyślne)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Wyczyść pamięć podręczną', diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php index c9755755e..4cdee8681 100644 --- a/app/i18n/pt-br/sub.php +++ b/app/i18n/pt-br/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath para:', ), 'rss' => 'RSS / Atom (padrão)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Limpar o cache', diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php index 5704b53b1..d13c4c4f0 100644 --- a/app/i18n/ru/sub.php +++ b/app/i18n/ru/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath для:', ), 'rss' => 'RSS / Atom (по умолчанию)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Очистить кэш', diff --git a/app/i18n/sk/sub.php b/app/i18n/sk/sub.php index f583f6ca0..3c980d202 100644 --- a/app/i18n/sk/sub.php +++ b/app/i18n/sk/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath pre:', ), 'rss' => 'RSS / Atom (prednastavené)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Vymazať vyrovnáciu pamäť', diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php index 056c059ac..3e03f667c 100644 --- a/app/i18n/tr/sub.php +++ b/app/i18n/tr/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath:', ), 'rss' => 'RSS / Atom (varsayılan)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => 'Önbelleği temizle', diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php index 2f9d17ace..5e6e570a9 100644 --- a/app/i18n/zh-cn/sub.php +++ b/app/i18n/zh-cn/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath 定位:', ), 'rss' => 'RSS / Atom (默认)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => '清理缓存', diff --git a/app/i18n/zh-tw/sub.php b/app/i18n/zh-tw/sub.php index dddcb2661..8a255645d 100644 --- a/app/i18n/zh-tw/sub.php +++ b/app/i18n/zh-tw/sub.php @@ -122,6 +122,7 @@ return array( 'xpath' => 'XPath 定位:', ), 'rss' => 'RSS / Atom (默認)', + 'xml_xpath' => 'XML + XPath', // TODO ), 'maintenance' => array( 'clear_cache' => '清理暫存', diff --git a/app/views/helpers/export/opml.phtml b/app/views/helpers/export/opml.phtml index eb6f7523b..64c83c960 100644 --- a/app/views/helpers/export/opml.phtml +++ b/app/views/helpers/export/opml.phtml @@ -18,8 +18,15 @@ function feedsToOutlines($feeds, $excludeMutedFeeds = false): array { 'description' => htmlspecialchars_decode($feed->description(), ENT_QUOTES), ]; - if ($feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH) { - $outline['type'] = FreshRSS_Export_Service::TYPE_HTML_XPATH; + if ($feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH || $feed->kind() === FreshRSS_Feed::KIND_XML_XPATH) { + switch ($feed->kind()) { + case FreshRSS_Feed::KIND_HTML_XPATH: + $outline['type'] = FreshRSS_Export_Service::TYPE_HTML_XPATH; + break; + case FreshRSS_Feed::KIND_XML_XPATH: + $outline['type'] = FreshRSS_Export_Service::TYPE_XML_XPATH; + break; + } /** @var array */ $xPathSettings = $feed->attributes('xpath'); $outline['frss:xPathItem'] = $xPathSettings['item'] ?? null; diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 5b958451d..0cd2ec0c3 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -391,8 +391,9 @@
diff --git a/app/views/subscription/add.phtml b/app/views/subscription/add.phtml index 7fa59e751..4e9da877f 100644 --- a/app/views/subscription/add.phtml +++ b/app/views/subscription/add.phtml @@ -70,6 +70,7 @@ diff --git a/docs/en/developers/OPML.md b/docs/en/developers/OPML.md index 2190a1de3..f65fd2faa 100644 --- a/docs/en/developers/OPML.md +++ b/docs/en/developers/OPML.md @@ -17,12 +17,14 @@ FreshRSS uses the XML namespace to export/import ext The list of the custom FreshRSS attributes can be seen in [the source code](https://github.com/FreshRSS/FreshRSS/blob/edge/app/views/helpers/export/opml.phtml), and here is an overview: -### HTML+XPath +### HTML+XPath or XML+XPath * ` ℹ️ [XPath 1.0](https://en.wikipedia.org/wiki/XPath) is a standard query language, which FreshRSS supports to enable [Web scraping](https://en.wikipedia.org/wiki/Web_scraping). +* ` $attributes */ function httpGet(string $url, string $cachePath, string $type = 'html', array $attributes = []): string { @@ -439,9 +443,15 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a $accept = '*/*;q=0.8'; switch ($type) { + case 'json': + $accept = 'application/json,application/javascript;q=0.9,text/javascript;q=0.8,*/*;q=0.7'; + break; case 'opml': $accept = 'text/x-opml,text/xml;q=0.9,application/xml;q=0.9,*/*;q=0.8'; break; + case 'xml': + $accept = 'application/xml,application/xhtml+xml,text/xml;q=0.9,*/*;q=0.8'; + break; case 'html': default: $accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; diff --git a/p/scripts/feed.js b/p/scripts/feed.js index 1a6833db6..29af2a3ea 100644 --- a/p/scripts/feed.js +++ b/p/scripts/feed.js @@ -88,10 +88,17 @@ function init_disable_elements_on_update(parent) { function init_select_show(parent) { const listener = (select) => { const options = select.querySelectorAll('option[data-show]'); + const shows = {}; // To allow multiple options to show the same element for (const option of options) { - const elem = document.getElementById(option.dataset.show); + if (!shows[option.dataset.show]) { + shows[option.dataset.show] = option.selected; + } + } + + for (const show in shows) { + const elem = document.getElementById(show); if (elem) { - elem.style.display = option.selected ? 'block' : 'none'; + elem.style.display = shows[show] ? 'block' : 'none'; } } }; -- cgit v1.2.3 From 60edc285281459a74f731836dffd20a693a80a21 Mon Sep 17 00:00:00 2001 From: mincerafter42 Date: Thu, 23 Feb 2023 11:14:55 -0800 Subject: Corrected `frss:xPathItemTitle` definition (#5140) --- docs/en/developers/OPML.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/en') diff --git a/docs/en/developers/OPML.md b/docs/en/developers/OPML.md index f65fd2faa..5191592a8 100644 --- a/docs/en/developers/OPML.md +++ b/docs/en/developers/OPML.md @@ -29,7 +29,7 @@ The following attributes are using similar naming conventions than [RSS-Bridge]( * `frss:xPathItem`: XPath expression for extracting the feed items from the source page. * Example: `//div[@class="news-item"]` -* `frss:xPathItemTitle`: XPath expression for extracting the feed title from the source page. +* `frss:xPathItemTitle`: XPath expression for extracting the item’s title from the item context. * Example: `descendant::h2` * `frss:xPathItemContent`: XPath expression for extracting an item’s content from the item context. * Example: `.` -- cgit v1.2.3 From 859c48383a229db43cf50ca64b09149bab0e3da4 Mon Sep 17 00:00:00 2001 From: maTh Date: Thu, 23 Feb 2023 22:20:36 +0100 Subject: docs: Minz Framwork (#5102) * done * Update docs/fr/developers/Minz/index.md Co-authored-by: Alexandre Alapetite --- docs/en/developers/03_Backend/05_Extensions.md | 190 +-------------- docs/en/developers/Minz/index.md | 198 ++++++++++++++- docs/fr/developers/03_Backend/02_Minz.md | 29 --- docs/fr/developers/03_Backend/05_Extensions.md | 324 +------------------------ docs/fr/developers/Minz/index.md | 249 +++++++++++++++++++ docs/fr/developers/Minz/migration.md | 3 + docs/fr/internationalization.md | 79 ++++++ 7 files changed, 521 insertions(+), 551 deletions(-) delete mode 100644 docs/fr/developers/03_Backend/02_Minz.md create mode 100644 docs/fr/developers/Minz/index.md create mode 100644 docs/fr/developers/Minz/migration.md create mode 100644 docs/fr/internationalization.md (limited to 'docs/en') diff --git a/docs/en/developers/03_Backend/05_Extensions.md b/docs/en/developers/03_Backend/05_Extensions.md index aa707d2e4..e86d73bfa 100644 --- a/docs/en/developers/03_Backend/05_Extensions.md +++ b/docs/en/developers/03_Backend/05_Extensions.md @@ -22,195 +22,9 @@ Another solution consists of an extension system. By allowing users to write the Note: it is quite conceivable that the functionalities of an extension can later be officially integrated into the FreshRSS code. Extensions make it easy to propose a proof of concept. -## Understanding basic mechanics (Minz and MVC) +## Minz Framework -**TODO** : move to 02_Minz.md - -This data sheet should refer to the official FreshRSS and Minz documentation (the PHP framework on which FreshRSS is based). Unfortunately, this documentation does not yet exist. In a few words, here are the main things you should know. It is not necessary to read all the chapters in this section if you don’t need to use a feature in your extension (if you don’t need to translate your extension, no need to know more about the `Minz_Translate` module for example). - -### MVC Architecture - -Minz relies on and imposes an MVC architecture on projects using it. This architecture consists of three main components: - -* The model: this is the base object that we will manipulate. In FreshRSS, categories, flows and articles are templates. The part of the code that makes it possible to manipulate them in a database is also part of the model but is separated from the base model: we speak of DAO (for "Data Access Object"). The templates are stored in a `Models` folder. -* The view: this is what the user sees. The view is therefore simply HTML code mixed with PHP to display dynamic information. The views are stored in a `views` folder. -* The controller: this is what makes it possible to link models and views. Typically, a controller will load templates from the database (like a list of items) to "pass" them to a view for display. Controllers are stored in a `Controllers` directory. - -### Routing - -In order to link a URL to a controller, first you have to go through a "routing" phase. In FreshRSS, this is particularly simple because it suffices to specify the name of the controller to load into the URL using a `c` parameter. -For example, the address will execute the code contained in the `hello` controller. - -One concept that has not yet been discussed is the "actions" system. An action is executed *on* a controller. Concretely, a controller is represented by a class and its actions by methods. To execute an action, it is necessary to specify an `a` parameter in the URL. - -Code example: - -```php -view->a_variable = 'FooBar'; - } - - public function worldAction() { - $this->view->a_variable = 'Hello World!'; - } -} - -?> -``` - -When loading the address , the `world` action is executed on the `hello` controller. - -Note: if `c` or `a` is not specified, the default value for each of these variables is `index`. -So the address will execute the `index` action of the `hello` controller. - -From now on, the `hello/world` naming convention will be used to refer to a controller/action pair. - -### Views - -Each view is associated with a controller and an action. The view associated with `hello/world` will be stored in a very specific file: `views/hello/world. phtml`. This convention is imposed by Minz. - -As explained above, the views consist of HTML mixed with PHP. Code example: - -```html -

- This is a parameter passed from the controller: a_variable ?> -

-``` - -The variable `$this->a_variable` is passed by the controller (see previous example). The difference is that in the controller it is necessary to pass `$this->view`, while in the view `$this` suffices. - -### Working with GET / POST - -It is often necessary to take advantage of parameters passed by GET or POST. In Minz, these parameters are accessible using the `Minz_Request` class. -Code example: - -```php - -``` - -The `Minz_Request::isPost()` method can be used to execute a piece of code only if it is a POST request. - -Note: it is preferable to use `Minz_Request` only in controllers. It is likely that you will encounter this method in FreshRSS views, or even in templates, but be aware that this is **not** good practice. - -### Access session settings - -The access to session parameters is strangely similar to the GET / POST parameters but passes through the `Minz_Session` class this time! There is no example here because you can repeat the previous example by changing all `Minz_Request` to `Minz_Session`. - -### Working with URLs - -To take full advantage of the Minz routing system, it is strongly discouraged to write hard URLs in your code. For example, the following view should be avoided: - -```html -

- Go to page Hello world! -

-``` - -If one day it was decided to use a "url rewriting" system to have addresses in a format, all previous addresses would become ineffective! - -So use the `Minz_Url` class and its `display()` method instead. `Minz_Url::display()` takes an array of the following form as its argument: - -```php - 'hello', - 'a' => 'world', - 'params' => [ - 'foo' => 'bar', - ], -]; - -// Show something like .?c=hello&a=world&foo=bar -echo Minz_Url::display($url_array); - -?> -``` - -Since this can become a bit tedious to use in the long run, especially in views, it is preferable to use the `_url()` shortcut: - -```php - -``` - -Note: as a general rule, the shortened form (`_url()`) should be used in views, while the long form (`Minz_Url::display()`) should be used in controllers. - -### Redirections - -It is often necessary to redirect a user to another page. To do so, the `Minz_Request` class offers another useful method: `forward()`. This method takes the same URL format as the one seen just before as its argument. - -Code example: - -```php - 'hello', - 'a' => 'world', -]; - -// Tells Minz to redirect the user to the hello / world page. -// Note that this is a redirection in the Minz sense of the term, not a redirection that the browser will have to manage (HTTP code 301 or 302) -// The code that follows forward() will thus be executed! -Minz_Request::forward($url_array); - -// To perform a type 302 redirect, add "true". -// The code that follows will never be executed. -Minz_Request::forward($url_array, true); - -?> -``` - -It is very common to want display a message to the user while performing a redirect, to tell the user how the action was carried out (validation of a form for example). Such a message is passed through a `notification` session variable (note: we will talk about feedback from now on to avoid confusion with a notification that can occur at any time). To facilitate this kind of very frequent action, there are two shortcuts that both perform a 302 redirect by assigning a feedback message: - -```php - 'hello', - 'a' => 'world', -]; -$feedback_good = 'All went well!'; -$feedback_bad = 'Oops, something went wrong.'; - -Minz_Request::good($feedback_good, $url_array); - -// or - -Minz_Request::bad($feedback_bad, $url_array); - -?> -``` - -### Translation Management - -This part [is explained here](/docs/en/internationalization.md). - -### Configuration management +see [Minz documentation](/docs/en/developers/Minz/index.md) ## Write an extension for FreshRSS diff --git a/docs/en/developers/Minz/index.md b/docs/en/developers/Minz/index.md index 9b6d46f17..ed5bc0482 100644 --- a/docs/en/developers/Minz/index.md +++ b/docs/en/developers/Minz/index.md @@ -1,19 +1,193 @@ -# Minz +# Minz Framework Minz is the homemade PHP framework used by FreshRSS. -The documentation is still incomplete and it would be great to explain: +This data sheet should refer to the official FreshRSS and Minz documentation (the PHP framework on which FreshRSS is based). Unfortunately, this documentation does not yet exist. In a few words, here are the main things you should know. It is not necessary to read all the chapters in this section if you don’t need to use a feature in your extension (if you don’t need to translate your extension, no need to know more about the `Minz_Translate` module for example). -- routing, controllers and actions -- configuration -- models and database -- views -- URLs management -- sessions -- internationalisation -- extensions -- mailer +## MVC Architecture + +Minz relies on and imposes an MVC architecture on projects using it. This architecture consists of three main components: + +* The model: this is the base object that we will manipulate. In FreshRSS, categories, flows and articles are templates. The part of the code that makes it possible to manipulate them in a database is also part of the model but is separated from the base model: we speak of DAO (for "Data Access Object"). The templates are stored in a `Models` folder. +* The view: this is what the user sees. The view is therefore simply HTML code mixed with PHP to display dynamic information. The views are stored in a `views` folder. +* The controller: this is what makes it possible to link models and views. Typically, a controller will load templates from the database (like a list of items) to "pass" them to a view for display. Controllers are stored in a `Controllers` directory. + +## Routing + +In order to link a URL to a controller, first you have to go through a "routing" phase. In FreshRSS, this is particularly simple because it suffices to specify the name of the controller to load into the URL using a `c` parameter. +For example, the address will execute the code contained in the `hello` controller. + +One concept that has not yet been discussed is the "actions" system. An action is executed *on* a controller. Concretely, a controller is represented by a class and its actions by methods. To execute an action, it is necessary to specify an `a` parameter in the URL. + +Code example: + +```php +view->a_variable = 'FooBar'; + } + + public function worldAction() { + $this->view->a_variable = 'Hello World!'; + } +} + +?> +``` + +When loading the address , the `world` action is executed on the `hello` controller. + +Note: if `c` or `a` is not specified, the default value for each of these variables is `index`. +So the address will execute the `index` action of the `hello` controller. + +From now on, the `hello/world` naming convention will be used to refer to a controller/action pair. + +## Views + +Each view is associated with a controller and an action. The view associated with `hello/world` will be stored in a very specific file: `views/hello/world. phtml`. This convention is imposed by Minz. + +As explained above, the views consist of HTML mixed with PHP. Code example: + +```html +

+ This is a parameter passed from the controller: a_variable ?> +

+``` + +The variable `$this->a_variable` is passed by the controller (see previous example). The difference is that in the controller it is necessary to pass `$this->view`, while in the view `$this` suffices. + +## Working with GET / POST + +It is often necessary to take advantage of parameters passed by GET or POST. In Minz, these parameters are accessible using the `Minz_Request` class. +Code example: + +```php + +``` + +The `Minz_Request::isPost()` method can be used to execute a piece of code only if it is a POST request. + +Note: it is preferable to use `Minz_Request` only in controllers. It is likely that you will encounter this method in FreshRSS views, or even in templates, but be aware that this is **not** good practice. + +## Access session settings + +The access to session parameters is strangely similar to the GET / POST parameters but passes through the `Minz_Session` class this time! There is no example here because you can repeat the previous example by changing all `Minz_Request` to `Minz_Session`. + +## Working with URLs + +To take full advantage of the Minz routing system, it is strongly discouraged to write hard URLs in your code. For example, the following view should be avoided: + +```html +

+ Go to page Hello world! +

+``` + +If one day it was decided to use a "url rewriting" system to have addresses in a format, all previous addresses would become ineffective! + +So use the `Minz_Url` class and its `display()` method instead. `Minz_Url::display()` takes an array of the following form as its argument: + +```php + 'hello', + 'a' => 'world', + 'params' => [ + 'foo' => 'bar', + ], +]; + +// Show something like .?c=hello&a=world&foo=bar +echo Minz_Url::display($url_array); + +?> +``` + +Since this can become a bit tedious to use in the long run, especially in views, it is preferable to use the `_url()` shortcut: + +```php + +``` + +Note: as a general rule, the shortened form (`_url()`) should be used in views, while the long form (`Minz_Url::display()`) should be used in controllers. + +## Redirections + +It is often necessary to redirect a user to another page. To do so, the `Minz_Request` class offers another useful method: `forward()`. This method takes the same URL format as the one seen just before as its argument. + +Code example: + +```php + 'hello', + 'a' => 'world', +]; + +// Tells Minz to redirect the user to the hello / world page. +// Note that this is a redirection in the Minz sense of the term, not a redirection that the browser will have to manage (HTTP code 301 or 302) +// The code that follows forward() will thus be executed! +Minz_Request::forward($url_array); + +// To perform a type 302 redirect, add "true". +// The code that follows will never be executed. +Minz_Request::forward($url_array, true); + +?> +``` + +It is very common to want display a message to the user while performing a redirect, to tell the user how the action was carried out (validation of a form for example). Such a message is passed through a `notification` session variable (note: we will talk about feedback from now on to avoid confusion with a notification that can occur at any time). To facilitate this kind of very frequent action, there are two shortcuts that both perform a 302 redirect by assigning a feedback message: + +```php + 'hello', + 'a' => 'world', +]; +$feedback_good = 'All went well!'; +$feedback_bad = 'Oops, something went wrong.'; + +Minz_Request::good($feedback_good, $url_array); + +// or + +Minz_Request::bad($feedback_bad, $url_array); + +?> +``` + +## Translation Management + +This part [is explained here](/docs/en/internationalization.md). + +## Migration Existing documentation includes: -- [How to manage migrations](migrations.md) +* [How to manage migrations](migrations.md) diff --git a/docs/fr/developers/03_Backend/02_Minz.md b/docs/fr/developers/03_Backend/02_Minz.md deleted file mode 100644 index 5daf684f0..000000000 --- a/docs/fr/developers/03_Backend/02_Minz.md +++ /dev/null @@ -1,29 +0,0 @@ -# Minz - -## Modèles - -> **À FAIRE** - -## Contrôleurs et actions - -> **À FAIRE** - -## Vues - -> **À FAIRE** - -## Routage - -> **À FAIRE** - -## Écriture des URL - -> **À FAIRE** - -## Internationalisation - -> **À FAIRE** - -## Comprendres les mécanismes internes - -> **À FAIRE** diff --git a/docs/fr/developers/03_Backend/05_Extensions.md b/docs/fr/developers/03_Backend/05_Extensions.md index a715c40b3..548aebf4f 100644 --- a/docs/fr/developers/03_Backend/05_Extensions.md +++ b/docs/fr/developers/03_Backend/05_Extensions.md @@ -36,329 +36,9 @@ puissent par la suite être intégrées dans le code initial de FreshRSS de façon officielle. Cela permet de proposer un « proof of concept » assez facilement. -## Comprendre les mécaniques de base (Minz et MVC) - -**TODO** : bouger dans 02_Minz.md - -Cette fiche technique devrait renvoyer vers la documentation officielle de -FreshRSS et de Minz (le framework PHP sur lequel repose -FreshRSS). Malheureusement cette documentation n’existe pas encore. Voici -donc en quelques mots les principaux éléments à connaître. Il n’est pas -nécessaire de lire l’ensemble des chapitres de cette section si vous n’avez -pas à utiliser une fonctionnalité dans votre extension (si vous n’avez pas -besoin de traduire votre extension, pas besoin d’en savoir plus sur le -module `Minz_Translate` par exemple). - -### Architecture MVC - -Minz repose et impose une architecture MVC pour les projets l’utilisant. On -distingue dans cette architecture trois composants principaux : - -* Le Modèle : c’est l’objet de base que l’on va manipuler. Dans FreshRSS, - les catégories, les flux et les articles sont des modèles. La partie du - code qui permet de les manipuler en base de données fait aussi partie du - modèle mais est séparée du modèle de base : on parle de DAO (pour « Data - Access Object »). Les modèles sont stockés dans un répertoire `Models`. -* La Vue : c’est ce qui représente ce que verra l’utilisateur. La vue est - donc simplement du code HTML que l’on mixe avec du PHP pour afficher les - informations dynamiques. Les vues sont stockées dans un répertoire - `views`. -* Le Contrôleur : c’est ce qui permet de lier modèles et vues entre - eux. Typiquement, un contrôleur va charger des modèles à partir de la base - de données (une liste d’articles par exemple) pour les « passer » à une - vue afin qu’elle les affiche. Les contrôleurs sont stockés dans un - répertoire `Controllers`. - -### Routage - -Afin de lier une URL à un contrôleur, on doit passer par une phase dite de « -routage ». Dans FreshRSS, cela est particulièrement simple car il suffit -d’indiquer le nom du contrôleur à charger dans l’URL à l’aide d’un paramètre `c`. -Par exemple, l’adresse va exécuter le code -contenu dans le contrôleur `hello`. - -Une notion qui n’a pas encore été évoquée est le système d'« actions ». Une -action est exécutée *sur* un contrôleur. Concrètement, un contrôleur va être -représenté par une classe et ses actions par des méthodes. Pour exécuter une -action, il est nécessaire d’indiquer un paramètre `a` dans l’URL. - -Exemple de code : - -```php -view->a_variable = 'FooBar'; - } - - public function worldAction() { - $this->view->a_variable = 'Hello World!'; - } -} - -?> -``` - -Si l’on charge l’adresse , l’action -`world` va donc être exécutée sur le contrôleur `hello`. - -Note : si `c` ou `a` n’est pas précisée, la valeur par défaut de chacune de -ces variables est `index`. Ainsi l’adresse va -exécuter l’action `index` du contrôleur `hello`. - -Plus loin, sera utilisée la convention `hello/world` pour évoquer un couple -contrôleur/action. - -### Vues - -Chaque vue est associée à un contrôleur et à une action. La vue associée à -`hello/world` va être stockée dans un fichier bien spécifique : -`views/hello/world.phtml`. Cette convention est imposée par Minz. - -Comme expliqué plus haut, les vues sont du code HTML mixé à du PHP. Exemple -de code : - -```html -

- Phrase passée en paramètre : a_variable ?> -

-``` - -La variable `$this->a_variable` a été passée précédemment par le contrôleur (voir exemple précédent). La différence est que dans le contrôleur il est nécessaire de passer par `$this->view` et que dans la vue `$this` suffit. - -### Accéder aux paramètres GET / POST - -Il est souvent nécessaire de profiter des paramètres passés par GET ou par -POST. Dans Minz, ces paramètres sont accessibles de façon indistincts à -l’aide de la classe `Minz_Request`. Exemple de code : - -```php - -``` - -La méthode `Minz_Request::isPost()` peut être utile pour n’exécuter un -morceau de code que s’il s’agit d’une requête POST. - -Note : il est préférable de n’utiliser `Minz_Request` que dans les -contrôleurs. Il est probable que vous rencontriez cette méthode dans les -vues de FreshRSS, voire dans les modèles, mais sachez qu’il ne s’agit -**pas** d’une bonne pratique. - -### Accéder aux paramètres de session - -L’accès aux paramètres de session est étrangement similaire aux paramètres -GET / POST mais passe par la classe `Minz_Session` cette fois-ci ! Il n’y a -pas d’exemple ici car vous pouvez reprendre le précédent en changeant tous -les `Minz_Request` par des `Minz_Session`. - -### Gestion des URL - -Pour profiter pleinement du système de routage de Minz, il est fortement -déconseillé d’écrire les URL en dur dans votre code. Par exemple, la vue -suivante doit être évitée : - -```html -

- Accéder à la page Hello world! -

-``` - -Si un jour il est décidé d’utiliser un système d'« url rewriting » pour -avoir des adresses au format , toutes -les adresses précédentes deviendraient ineffectives ! - -Préférez donc l’utilisation de la classe `Minz_Url` et de sa méthode -`display()`. `Minz_Url::display()` prend en paramètre un tableau de la forme -suivante : - -```php - 'hello', - 'a' => 'world', - 'params' => [ - 'foo' => 'bar', - ], -]; - -// Affichera quelque chose comme .?c=hello&a=world&foo=bar -echo Minz_Url::display($url_array); - -?> -``` - -Comme cela peut devenir un peu pénible à utiliser à la longue, surtout dans -les vues, il est préférable d’utiliser le raccourci `_url()` : - -```php - -``` - -Note : en règle générale, la forme raccourcie (`_url()`) doit être utilisée -dans les vues tandis que la forme longue (`Minz_Url::display()`) doit être -utilisée dans les contrôleurs. - -### Redirections - -Il est souvent nécessaire de rediriger un utilisateur vers une autre -page. Pour cela, la classe `Minz_Request` dispose d’une autre méthode utile -: `forward()`. Cette méthode prend en argument le même format d’URL que -celui vu juste avant. - -Exemple de code : - -```php - 'hello', - 'a' => 'world', -]; - -// Indique à Minz de rediriger l’utilisateur vers la page hello/world. -// Notez qu’il s’agit d’une redirection au sens Minz du terme, pas d’une redirection que le navigateur va avoir à gérer (code HTTP 301 ou 302) -// Le code qui suit forward() va ainsi être exécuté ! -Minz_Request::forward($url_array); - -// Pour effectuer une redirection type 302, ajoutez "true". -// Le code qui suivra ne sera alors jamais exécuté. -Minz_Request::forward($url_array, true); - -?> -``` - -Il est très fréquent de vouloir effectuer une redirection tout en affichant -un message à l’utilisateur pour lui indiquer comment s’est déroulée l’action -effectuée juste avant (validation d’un formulaire par exemple). Un tel -message est passé par une variable de session `notification` (note : nous -parlerons plutôt de « feedback » désormais pour éviter la confusion avec une -notification qui peut survenir à tout moment). Pour faciliter ce genre -d’action très fréquente, il existe deux raccourcis qui effectuent tout deux -une redirection type 302 en affectant un message de feedback : - -```php - 'hello', - 'a' => 'world', -]; -$feedback_good = 'Tout s’est bien passé !'; -$feedback_bad = 'Oups, quelque chose n’a pas marché.'; - -Minz_Request::good($feedback_good, $url_array); - -// ou - -Minz_Request::bad($feedback_bad, $url_array); - -?> -``` - -### Gestion de la traduction - -Il est fréquent (et c’est un euphémisme) de vouloir afficher des phrases à -l’utilisateur. Dans l’exemple précédent par exemple, nous affichions un -feedback à l’utilisateur en fonction du résultat d’une validation de -formulaire. Le problème est que FreshRSS possède des utilisateurs de -différentes nationalités. Il est donc nécessaire de pouvoir gérer -différentes langues pour ne pas rester cantonné à l’Anglais ou au Français. - -La solution consiste à utiliser la classe `Minz_Translate` qui permet de -traduire dynamiquement FreshRSS (ou toute application basée sur Minz). Avant -d’utiliser ce module, il est nécessaire de savoir où trouver les chaînes de -caractères à traduire. Chaque langue possède son propre sous-répertoire dans -un répertoire parent nommé `i18n`. Par exemple, les fichiers de langue en -Français sont situés dans `i18n/fr/`. Il existe sept fichiers différents : - -* `admin.php` pour tout ce qui est relatif à l’administration de FreshRSS ; -* `conf.php` pour l’aspect configuration ; -* `feedback.php` contient les traductions des messages de feedback ; -* `gen.php` stocke ce qui est global à FreshRSS (gen pour « general ») ; -* `index.php` pour la page principale qui liste les flux et la page « À propos » ; -* `install.php` contient les phrases relatives à l’installation de FreshRSS ; -* `sub.php` pour l’aspect gestion des abonnements (sub pour « subscription »). - -Cette organisation permet de ne pas avoir un unique énorme fichier de -traduction. - -Les fichiers de traduction sont assez simples : il s’agit seulement de -retourner un tableau PHP contenant les traductions. Extrait du fichier -`app/i18n/fr/gen.php` : - -```php - [ - 'actualize' => 'Actualiser', - 'back_to_rss_feeds' => '← Retour à vos flux RSS', - 'cancel' => 'Annuler', - 'create' => 'Créer', - 'disable' => 'Désactiver', - ), - 'freshrss' => array( - '_' => 'FreshRSS', - 'about' => 'À propos de FreshRSS', - ), -]; - -?> -``` - -Pour accéder à ces traductions, `Minz_Translate` va nous aider à l’aide de -sa méthode `Minz_Translate::t()`. Comme cela peut être un peu long à taper, -il a été introduit un raccourci qui **doit** être utilisé en toutes -circonstances : `_t()`. Exemple de code : - -```html -

- - - -

-``` +## Minz Framework -La chaîne à passer à la fonction `_t()` consiste en une série d’identifiants -séparés par des points. Le premier identifiant indique de quel fichier on -veut extraire la traduction (dans notre cas présent, de `gen.php`), tandis -que les suivantes indiquent des entrées de tableaux. Ainsi `action` est une -entrée du tableau principal et `back_to_rss_feeds` est une entrée du tableau -`action`. Cela permet d’organiser encore un peu plus nos fichiers de -traduction. - -Il existe un petit cas particulier qui permet parfois de se simplifier la -vie : le cas de l’identifiant `_`. Celui-ci doit nécessairement être présent -en bout de chaîne et permet de donner une valeur à l’identifiant de niveau -supérieur. C’est assez dur à expliquer mais très simple à comprendre. Dans -l’exemple donné plus haut, un `_` est associé à la valeur `FreshRSS` : cela -signifie qu’il n’y a pas besoin d’écrire `_t('gen.freshrss._')` mais -`_t('gen.freshrss')` suffit. - -### Gestion de la configuration +see [Minz documentation](/docs/fr/developers/Minz/index.md) ## Écrire une extension pour FreshRSS diff --git a/docs/fr/developers/Minz/index.md b/docs/fr/developers/Minz/index.md new file mode 100644 index 000000000..0d1d2124a --- /dev/null +++ b/docs/fr/developers/Minz/index.md @@ -0,0 +1,249 @@ +# Minz + +Cette fiche technique devrait renvoyer vers la documentation officielle de +FreshRSS et de Minz (le framework PHP sur lequel repose +FreshRSS). Malheureusement cette documentation n’existe pas encore. Voici +donc en quelques mots les principaux éléments à connaître. Il n’est pas +nécessaire de lire l’ensemble des chapitres de cette section si vous n’avez +pas à utiliser une fonctionnalité dans votre extension (si vous n’avez pas +besoin de traduire votre extension, pas besoin d’en savoir plus sur le +module `Minz_Translate` par exemple). + +## Architecture MVC + +Minz repose et impose une architecture MVC pour les projets l’utilisant. On +distingue dans cette architecture trois composants principaux : + +* Le Modèle : c’est l’objet de base que l’on va manipuler. Dans FreshRSS, + les catégories, les flux et les articles sont des modèles. La partie du + code qui permet de les manipuler en base de données fait aussi partie du + modèle mais est séparée du modèle de base : on parle de DAO (pour « Data + Access Object »). Les modèles sont stockés dans un répertoire `Models`. +* La Vue : c’est ce qui représente ce que verra l’utilisateur. La vue est + donc simplement du code HTML que l’on mixe avec du PHP pour afficher les + informations dynamiques. Les vues sont stockées dans un répertoire + `views`. +* Le Contrôleur : c’est ce qui permet de lier modèles et vues entre + eux. Typiquement, un contrôleur va charger des modèles à partir de la base + de données (une liste d’articles par exemple) pour les « passer » à une + vue afin qu’elle les affiche. Les contrôleurs sont stockés dans un + répertoire `Controllers`. + +## Routage + +Afin de lier une URL à un contrôleur, on doit passer par une phase dite de « +routage ». Dans FreshRSS, cela est particulièrement simple car il suffit +d’indiquer le nom du contrôleur à charger dans l’URL à l’aide d’un paramètre `c`. +Par exemple, l’adresse va exécuter le code +contenu dans le contrôleur `hello`. + +Une notion qui n’a pas encore été évoquée est le système d'« actions ». Une +action est exécutée *sur* un contrôleur. Concrètement, un contrôleur va être +représenté par une classe et ses actions par des méthodes. Pour exécuter une +action, il est nécessaire d’indiquer un paramètre `a` dans l’URL. + +Exemple de code : + +```php +view->a_variable = 'FooBar'; + } + + public function worldAction() { + $this->view->a_variable = 'Hello World!'; + } +} + +?> +``` + +Si l’on charge l’adresse , l’action +`world` va donc être exécutée sur le contrôleur `hello`. + +Note : si `c` ou `a` n’est pas précisée, la valeur par défaut de chacune de +ces variables est `index`. Ainsi l’adresse va +exécuter l’action `index` du contrôleur `hello`. + +Plus loin, sera utilisée la convention `hello/world` pour évoquer un couple +contrôleur/action. + +## Vues + +Chaque vue est associée à un contrôleur et à une action. La vue associée à +`hello/world` va être stockée dans un fichier bien spécifique : +`views/hello/world.phtml`. Cette convention est imposée par Minz. + +Comme expliqué plus haut, les vues sont du code HTML mixé à du PHP. Exemple +de code : + +```html +

+ Phrase passée en paramètre : a_variable ?> +

+``` + +La variable `$this->a_variable` a été passée précédemment par le contrôleur (voir exemple précédent). La différence est que dans le contrôleur il est nécessaire de passer par `$this->view` et que dans la vue `$this` suffit. + +## Accéder aux paramètres GET / POST + +Il est souvent nécessaire de profiter des paramètres passés par GET ou par +POST. Dans Minz, ces paramètres sont accessibles de façon indistincts à +l’aide de la classe `Minz_Request`. Exemple de code : + +```php + +``` + +La méthode `Minz_Request::isPost()` peut être utile pour n’exécuter un +morceau de code que s’il s’agit d’une requête POST. + +Note : il est préférable de n’utiliser `Minz_Request` que dans les +contrôleurs. Il est probable que vous rencontriez cette méthode dans les +vues de FreshRSS, voire dans les modèles, mais sachez qu’il ne s’agit +**pas** d’une bonne pratique. + +## Accéder aux paramètres de session + +L’accès aux paramètres de session est étrangement similaire aux paramètres +GET / POST mais passe par la classe `Minz_Session` cette fois-ci ! Il n’y a +pas d’exemple ici car vous pouvez reprendre le précédent en changeant tous +les `Minz_Request` par des `Minz_Session`. + +## Gestion des URL + +Pour profiter pleinement du système de routage de Minz, il est fortement +déconseillé d’écrire les URL en dur dans votre code. Par exemple, la vue +suivante doit être évitée : + +```html +

+ Accéder à la page Hello world! +

+``` + +Si un jour il est décidé d’utiliser un système d'« url rewriting » pour +avoir des adresses au format , toutes +les adresses précédentes deviendraient ineffectives ! + +Préférez donc l’utilisation de la classe `Minz_Url` et de sa méthode +`display()`. `Minz_Url::display()` prend en paramètre un tableau de la forme +suivante : + +```php + 'hello', + 'a' => 'world', + 'params' => [ + 'foo' => 'bar', + ], +]; + +// Affichera quelque chose comme .?c=hello&a=world&foo=bar +echo Minz_Url::display($url_array); + +?> +``` + +Comme cela peut devenir un peu pénible à utiliser à la longue, surtout dans +les vues, il est préférable d’utiliser le raccourci `_url()` : + +```php + +``` + +Note : en règle générale, la forme raccourcie (`_url()`) doit être utilisée +dans les vues tandis que la forme longue (`Minz_Url::display()`) doit être +utilisée dans les contrôleurs. + +## Redirections + +Il est souvent nécessaire de rediriger un utilisateur vers une autre +page. Pour cela, la classe `Minz_Request` dispose d’une autre méthode utile +: `forward()`. Cette méthode prend en argument le même format d’URL que +celui vu juste avant. + +Exemple de code : + +```php + 'hello', + 'a' => 'world', +]; + +// Indique à Minz de rediriger l’utilisateur vers la page hello/world. +// Notez qu’il s’agit d’une redirection au sens Minz du terme, pas d’une redirection que le navigateur va avoir à gérer (code HTTP 301 ou 302) +// Le code qui suit forward() va ainsi être exécuté ! +Minz_Request::forward($url_array); + +// Pour effectuer une redirection type 302, ajoutez "true". +// Le code qui suivra ne sera alors jamais exécuté. +Minz_Request::forward($url_array, true); + +?> +``` + +Il est très fréquent de vouloir effectuer une redirection tout en affichant +un message à l’utilisateur pour lui indiquer comment s’est déroulée l’action +effectuée juste avant (validation d’un formulaire par exemple). Un tel +message est passé par une variable de session `notification` (note : nous +parlerons plutôt de « feedback » désormais pour éviter la confusion avec une +notification qui peut survenir à tout moment). Pour faciliter ce genre +d’action très fréquente, il existe deux raccourcis qui effectuent tout deux +une redirection type 302 en affectant un message de feedback : + +```php + 'hello', + 'a' => 'world', +]; +$feedback_good = 'Tout s’est bien passé !'; +$feedback_bad = 'Oups, quelque chose n’a pas marché.'; + +Minz_Request::good($feedback_good, $url_array); + +// ou + +Minz_Request::bad($feedback_bad, $url_array); + +?> +``` + +## Gestion de la traduction + +Cette partie est [expliquée dans la page dédiée](/docs/fr/internationalization.md). + +## Migration + +Existing documentation includes: + +* [How to manage migrations](migrations.md) diff --git a/docs/fr/developers/Minz/migration.md b/docs/fr/developers/Minz/migration.md new file mode 100644 index 000000000..ad2eef949 --- /dev/null +++ b/docs/fr/developers/Minz/migration.md @@ -0,0 +1,3 @@ +# Migration + +see [English documentation](/docs/en/developers/Minz/migrations.md) diff --git a/docs/fr/internationalization.md b/docs/fr/internationalization.md new file mode 100644 index 000000000..532ed457d --- /dev/null +++ b/docs/fr/internationalization.md @@ -0,0 +1,79 @@ +# Gestion de la traduction + +Il est fréquent (et c’est un euphémisme) de vouloir afficher des phrases à +l’utilisateur. Dans l’exemple précédent par exemple, nous affichions un +feedback à l’utilisateur en fonction du résultat d’une validation de +formulaire. Le problème est que FreshRSS possède des utilisateurs de +différentes nationalités. Il est donc nécessaire de pouvoir gérer +différentes langues pour ne pas rester cantonné à l’Anglais ou au Français. + +La solution consiste à utiliser la classe `Minz_Translate` qui permet de +traduire dynamiquement FreshRSS (ou toute application basée sur Minz). Avant +d’utiliser ce module, il est nécessaire de savoir où trouver les chaînes de +caractères à traduire. Chaque langue possède son propre sous-répertoire dans +un répertoire parent nommé `i18n`. Par exemple, les fichiers de langue en +Français sont situés dans `i18n/fr/`. Il existe sept fichiers différents : + +* `admin.php` pour tout ce qui est relatif à l’administration de FreshRSS ; +* `conf.php` pour l’aspect configuration ; +* `feedback.php` contient les traductions des messages de feedback ; +* `gen.php` stocke ce qui est global à FreshRSS (gen pour « general ») ; +* `index.php` pour la page principale qui liste les flux et la page « À propos » ; +* `install.php` contient les phrases relatives à l’installation de FreshRSS ; +* `sub.php` pour l’aspect gestion des abonnements (sub pour « subscription »). + +Cette organisation permet de ne pas avoir un unique énorme fichier de +traduction. + +Les fichiers de traduction sont assez simples : il s’agit seulement de +retourner un tableau PHP contenant les traductions. Extrait du fichier +`app/i18n/fr/gen.php` : + +```php + [ + 'actualize' => 'Actualiser', + 'back_to_rss_feeds' => '← Retour à vos flux RSS', + 'cancel' => 'Annuler', + 'create' => 'Créer', + 'disable' => 'Désactiver', + ), + 'freshrss' => array( + '_' => 'FreshRSS', + 'about' => 'À propos de FreshRSS', + ), +]; + +?> +``` + +Pour accéder à ces traductions, `Minz_Translate` va nous aider à l’aide de +sa méthode `Minz_Translate::t()`. Comme cela peut être un peu long à taper, +il a été introduit un raccourci qui **doit** être utilisé en toutes +circonstances : `_t()`. Exemple de code : + +```html +

+ + + +

+``` + +La chaîne à passer à la fonction `_t()` consiste en une série d’identifiants +séparés par des points. Le premier identifiant indique de quel fichier on +veut extraire la traduction (dans notre cas présent, de `gen.php`), tandis +que les suivantes indiquent des entrées de tableaux. Ainsi `action` est une +entrée du tableau principal et `back_to_rss_feeds` est une entrée du tableau +`action`. Cela permet d’organiser encore un peu plus nos fichiers de +traduction. + +Il existe un petit cas particulier qui permet parfois de se simplifier la +vie : le cas de l’identifiant `_`. Celui-ci doit nécessairement être présent +en bout de chaîne et permet de donner une valeur à l’identifiant de niveau +supérieur. C’est assez dur à expliquer mais très simple à comprendre. Dans +l’exemple donné plus haut, un `_` est associé à la valeur `FreshRSS` : cela +signifie qu’il n’y a pas besoin d’écrire `_t('gen.freshrss._')` mais +`_t('gen.freshrss')` suffit. -- cgit v1.2.3 From 4f957dfc4c38c418e5b46a2dc8d34a9bdabb31db Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 28 Feb 2023 08:11:27 +0100 Subject: Doc git latest (#5148) #fix https://github.com/FreshRSS/FreshRSS/issues/4949 --- README.fr.md | 5 +++-- docs/en/admins/07_LinuxUpdate.md | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'docs/en') diff --git a/README.fr.md b/README.fr.md index 221385ab5..559a57745 100644 --- a/README.fr.md +++ b/README.fr.md @@ -109,8 +109,9 @@ sudo apt-get install git sudo git clone https://github.com/FreshRSS/FreshRSS.git cd FreshRSS -# Si vous souhaitez utiliser la dernière version stable de FreshRSS -sudo git checkout $(git describe --tags --abbrev=0) +# La branche par défault “edge” est la celle de la publication continue, +# mais vous pouvez changer de branche pour “latest” si vous préférez les versions stables de FreshRSS +sudo git checkout latest # Mettre les droits d’accès pour le serveur Web sudo cli/access-permissions.sh diff --git a/docs/en/admins/07_LinuxUpdate.md b/docs/en/admins/07_LinuxUpdate.md index 27e8ef451..47b84e5ef 100644 --- a/docs/en/admins/07_LinuxUpdate.md +++ b/docs/en/admins/07_LinuxUpdate.md @@ -49,18 +49,18 @@ If your local user doesn’t have write access to the FreshRSS folder, use a sud 4. Update FreshRSS ```sh git checkout edge - git pull - git checkout $(git describe --tags --abbrev=0) + git pull --ff-only ``` - Note: If you want to use the rolling release, the last command is optional. + > ℹ️ Use `edge` for the rolling release or `latest` for the latest stable release. 5. (optional) Make sure you use the correct version ```sh git status ``` - The command should tell you the tag that you’re using. It must be the same as the one associated with [the latest release on GitHub](https://github.com/FreshRSS/FreshRSS/releases/latest). If you use the rolling release, it should tell you that your `edge` branch is up to date with `origin`. + The command should tell you the branch that you’re using. It must be the same as the one associated with [the latest release on GitHub](https://github.com/FreshRSS/FreshRSS/releases/latest). + If you use the rolling release, it should tell you that your `edge` branch is up to date with `origin`. 6. Re-set correct permissions so that your web server can access the files ```sh -- cgit v1.2.3