diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 08d0a5afe..49687f7af 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,41 +14,38 @@ jobs:
strategy:
fail-fast: false
matrix:
- ruby: ['2.6', '2.7', '3.0', 'jruby', 'truffleruby']
- gemfile: ['gemfiles/activerecord_5.0.2.gemfile', 'gemfiles/activerecord_5.1.0.gemfile', 'gemfiles/activerecord_5.2.2.gemfile', 'gemfiles/activerecord_6.0.0.gemfile', 'gemfiles/activerecord_6.1.0.gemfile', 'gemfiles/activerecord_main.gemfile']
+ ruby: ['2.7', '3.0', '3.1', '3.2', '3.3']
+ gemfile: ['gemfiles/activerecord_5.2.2.gemfile', 'gemfiles/activerecord_6.0.0.gemfile', 'gemfiles/activerecord_6.1.0.gemfile', 'gemfiles/activerecord_7.0.0.gemfile', 'gemfiles/activerecord_7.1.0.gemfile', 'gemfiles/activerecord_main.gemfile']
include:
+ - gemfile: 'gemfiles/activerecord_7.1.0.gemfile'
+ ruby: '3.3'
+ - gemfile: 'gemfiles/activerecord_7.1.0.gemfile'
+ ruby: '3.0'
- gemfile: 'gemfiles/activerecord_7.0.0.gemfile'
- ruby: '3.1'
+ ruby: '3.3'
- gemfile: 'gemfiles/activerecord_7.0.0.gemfile'
ruby: '3.0'
- gemfile: 'gemfiles/activerecord_6.1.0.gemfile'
- ruby: '3.1'
+ ruby: '3.3'
- gemfile: 'gemfiles/activerecord_6.1.0.gemfile'
ruby: '3.0'
exclude:
- gemfile: 'gemfiles/activerecord_5.2.2.gemfile'
- ruby: '3.0' # rails 5.2 can't run on ruby 3.0
- - gemfile: 'gemfiles/activerecord_5.1.0.gemfile'
- ruby: '3.0' # rails 5.1 can't run on ruby 3.0
- - gemfile: 'gemfiles/activerecord_5.0.2.gemfile'
- ruby: '3.0' # rails 5.0 can't run on ruby 3.0
- - gemfile: 'gemfiles/activerecord_5.0.2.gemfile'
- ruby: '3.0' # rails 5.0 can't run on ruby 3.0
- - gemfile: 'gemfiles/activerecord_5.0.2.gemfile'
- ruby: 'truffleruby' # TruffleRuby 21.0 targets Ruby 2.7, same as above
- - gemfile: 'gemfiles/activerecord_5.1.0.gemfile'
- ruby: 'truffleruby' # TruffleRuby 21.0 targets Ruby 2.7, same as above
+ ruby: '3.0'
+ - gemfile: 'gemfiles/activerecord_5.2.2.gemfile'
+ ruby: '3.1'
- gemfile: 'gemfiles/activerecord_5.2.2.gemfile'
- ruby: 'truffleruby' # TruffleRuby 21.0 targets Ruby 2.7, same as above
+ ruby: '3.2'
+ - gemfile: 'gemfiles/activerecord_5.2.2.gemfile'
+ ruby: '3.3'
+ - gemfile: 'gemfiles/activerecord_7.0.0.gemfile'
+ ruby: '2.7'
+ - gemfile: 'gemfiles/activerecord_7.1.0.gemfile'
+ ruby: '2.7'
- gemfile: 'gemfiles/activerecord_main.gemfile'
- ruby: '2.6' # rails 7+ requires ruby 3.0+
- - gemfile: 'gemfiles/activerecord_5.0.2.gemfile'
- ruby: 'jruby' # this *should* work - there's a test failure; it's not incompatible like the other excludes. could be an issue in Rails 5.0.2?
- - gemfile: 'gemfiles/activerecord_6.1.0.gemfile'
- ruby: 'jruby' # this *should* work. it seems like there's an issue with rails 6 on jruby.
+ ruby: '2.7'
- gemfile: 'gemfiles/activerecord_main.gemfile'
- ruby: 'jruby' # this *should* work. it seems like there's an issue with rails 6 on jruby.
-
+ ruby: '3.0'
env:
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
@@ -84,10 +81,10 @@ jobs:
bundler-cache: true
- name: Run tests on sqlite
- run: DB=sqlite bundle exec rake
+ run: DB=sqlite bundle exec rspec
- name: Run tests on postgres
- run: DB=postgres bundle exec rake
+ run: DB=postgres bundle exec rspec
lint:
name: Lint
diff --git a/.gitignore b/.gitignore
index 5b936d516..4eb7b201c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,6 @@ Gemfile.lock
.ruby-version
.ruby-gemset
/tmp
+.vitepress/cache
+node_modules
+.vitepress/dist
diff --git a/.rubocop.yml b/.rubocop.yml
index 8585e75c6..24763717e 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -50,3 +50,4 @@ AllCops:
- 'gemfiles/**/*'
- 'vendor/**/*'
- 'Appraisals'
+ - 'node_modules/**/*'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index f6c643ac7..1715d17ee 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -214,3 +214,6 @@ Style/StringChars:
Style/StringConcatenation:
Exclude:
- 'lib/cancan/rule.rb'
+
+Lint/SafeNavigationChain:
+ Enabled: false
diff --git a/Appraisals b/Appraisals
index d025b2d22..2bb71a217 100644
--- a/Appraisals
+++ b/Appraisals
@@ -1,37 +1,3 @@
-appraise 'activerecord_5.0.2' do
- gem 'activerecord', '~> 5.0.2', require: 'active_record'
- gem 'activesupport', '~> 5.0.2', require: 'active_support/all'
- gem 'actionpack', '~> 5.0.2', require: 'action_pack'
-
- gemfile.platforms :jruby do
- gem 'activerecord-jdbcsqlite3-adapter'
- gem 'jdbc-sqlite3'
- gem 'jdbc-postgres'
- end
-
- gemfile.platforms :ruby, :mswin, :mingw do
- gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.3.0'
- end
-end
-
-appraise 'activerecord_5.1.0' do
- gem 'activerecord', '~> 5.1.0', require: 'active_record'
- gem 'activesupport', '~> 5.1.0', require: 'active_support/all'
- gem 'actionpack', '~> 5.1.0', require: 'action_pack'
-
- gemfile.platforms :jruby do
- gem 'activerecord-jdbcsqlite3-adapter'
- gem 'jdbc-sqlite3'
- gem 'jdbc-postgres'
- end
-
- gemfile.platforms :ruby, :mswin, :mingw do
- gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.4.2'
- end
-end
-
appraise 'activerecord_5.2.2' do
gem 'activerecord', '~> 5.2.2', require: 'active_record'
gem 'activesupport', '~> 5.2.2', require: 'active_support/all'
@@ -45,7 +11,7 @@ appraise 'activerecord_5.2.2' do
gemfile.platforms :ruby, :mswin, :mingw do
gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.4.2'
+ gem 'sqlite3', '~> 1.7.3'
end
end
@@ -62,7 +28,7 @@ appraise 'activerecord_6.0.0' do
platforms :ruby, :mswin, :mingw do
gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.4.2'
+ gem 'sqlite3', '~> 1.7.3'
end
end
@@ -79,7 +45,7 @@ appraise 'activerecord_6.1.0' do
platforms :ruby, :mswin, :mingw do
gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.4.2'
+ gem 'sqlite3', '~> 1.7.3'
end
end
@@ -96,7 +62,24 @@ appraise 'activerecord_7.0.0' do
platforms :ruby, :mswin, :mingw do
gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.4.2'
+ gem 'sqlite3', '~> 1.7.3'
+ end
+end
+
+appraise 'activerecord_7.1.0' do
+ gem 'actionpack', '~> 7.1.0', require: 'action_pack'
+ gem 'activerecord', '~> 7.1.0', require: 'active_record'
+ gem 'activesupport', '~> 7.1.0', require: 'active_support/all'
+
+ platforms :jruby do
+ gem 'activerecord-jdbcsqlite3-adapter'
+ gem 'jdbc-sqlite3'
+ gem 'jdbc-postgres'
+ end
+
+ platforms :ruby, :mswin, :mingw do
+ gem 'pg', '~> 1.5.6'
+ gem 'sqlite3', '~> 1.7.3'
end
end
@@ -114,7 +97,7 @@ appraise 'activerecord_main' do
end
platforms :ruby, :mswin, :mingw do
- gem 'pg', '~> 1.3.4'
- gem 'sqlite3', '~> 1.4.2'
+ gem 'pg', '~> 1.5.6'
+ gem 'sqlite3', '~> 1.7.3'
end
end
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 265e7f542..c8a88d2d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 3.6.0
+
+* [#849](https://github.com/CanCanCommunity/cancancan/pull/849): Update tests matrix. ([@coorasse][])
+* [#843](https://github.com/CanCanCommunity/cancancan/pull/843): Compress duplicate rules. ([@MrChoclate][])
+* [#841](https://github.com/CanCanCommunity/cancancan/pull/841): New https://cancancan.dev website. ([@pandermatt][])
+* [#839](https://github.com/CanCanCommunity/cancancan/pull/839): switch from database column detection to Rails attributes detection. ([@kalsan][])
## 3.5.0
* [#653](https://github.com/CanCanCommunity/cancancan/pull/653): Add support for using an nil relation as a condition. ([@ghiculescu][])
@@ -707,3 +713,6 @@ Please read the [guide on migrating from CanCanCan 2.x to 3.0](https://github.co
[@Juleffel]: https://github.com/Juleffel
[@honigc]: https://github.com/honigc
[@WriterZephos]: https://github.com/WriterZephos
+[@MrChoclate]: https://github.com/MrChoclate
+[@pandermatt]: https://github.com/pandermatt
+[@kalsan]: https://github.com/kalsan
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7252e2f31..a925aa7e2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -25,3 +25,19 @@ Please make sure you have test coverage for anything you add or fix!
Please add a CHANGELOG entry with any relevant tags for issues, pull-requests, and authors.
Thanks for you contribution!
+
+### Modify the Documentation
+
+The documentation is written in Markdown and is located in the `docs` directory. The documentation is built using [VitePress](https://vitepress.dev).
+VitePress supports all markdown features but also adds a few enhancements, which are documented in the [Markdown Extensions](https://vitepress.dev/guide/markdown).
+
+```bash
+npm install
+npm run dev
+
+# build for production, resulting in a static site in docs/.vitepress/dist
+npm run build
+```
+
+Before submitting a pull request, please make sure the documentation builds correctly using `npm run build`.
+Most likely the build will fail if there are any syntax errors in the markdown files or dead links.
diff --git a/README.md b/README.md
index 04fa2b68b..1e84f0de3 100644
--- a/README.md
+++ b/README.md
@@ -26,20 +26,14 @@ of models automatically and reduce duplicated code.
## Our sponsors
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -50,20 +44,8 @@ of models automatically and reduce duplicated code.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
new file mode 100644
index 000000000..d492843d7
--- /dev/null
+++ b/docs/.vitepress/config.mts
@@ -0,0 +1,97 @@
+import { defineConfig } from 'vitepress'
+
+// https://vitepress.dev/reference/site-config
+export default defineConfig({
+ title: "CanCanCan",
+ description: "The authorization Gem for Ruby on Rails.",
+ head: [
+ ['link', { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" }],
+ ['link', { rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" }],
+ ['link', { rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon-16x16.png" }],
+ ['link', { rel: "mask-icon", href: "./safari-pinned-tab.svg", color: "#3c3ebf" }],
+
+ ['link', { rel: "icon", href: "/favicon.ico", type: "image/x-icon" }],
+ ['link', { rel: "shortcut icon", href: "/favicon.ico", type: "image/x-icon" }],
+ ],
+ sitemap: {
+ hostname: 'https://cancancan.dev'
+ },
+ cleanUrls: true,
+ themeConfig: {
+ // https://vitepress.dev/reference/default-theme-config
+ nav: [
+ { text: 'Docs', link: '/README' },
+ { text: 'Changelog', link: 'https://github.com/CanCanCommunity/cancancan/blob/main/CHANGELOG.md' },
+ {
+ text: 'Screencasts',
+ items: [
+ { text: 'Screencast 1', link: 'http://railscasts.com/episodes/192-authorization-with-cancan' },
+ { text: 'Screencast 2', link: 'https://www.youtube.com/watch?v=cTYu-OjUgDw' }
+ ]
+ },
+ ],
+
+ footer: {
+ message: 'Made with ❤️ by the CanCanCan community',
+ copyright: `${new Date().getFullYear()} CanCanCan`
+ },
+ externalLinkIcon: true,
+
+ lastUpdated: {
+ formatOptions: {
+ dateStyle: 'medium',
+ }
+ },
+ editLink: {
+ pattern: 'https://github.com/CanCanCommunity/cancancan/edit/main/docs/:path'
+ },
+ search: {
+ provider: 'local'
+ },
+
+ logo: '/cancancan.png',
+
+ sidebar: [
+ {
+ text: 'Guide',
+ items: [
+ { text: 'Introduction', link: '/introduction' },
+ { text: 'Installation', link: '/installation' },
+ { text: 'Define and check abilities', link: '/define_check_abilities' },
+ { text: 'Controller helpers', link: '/controller_helpers' },
+ { text: 'Fetching records', link: '/fetching_records' },
+ { text: 'Cannot', link: '/cannot' },
+ { text: 'Hash of conditions', link: '/hash_of_conditions' },
+ { text: 'Combine Abilities', link: '/combine_abilities' },
+ { text: 'Check abilities - avoid mistakes', link: '/check_abilities_mistakes' },
+ { text: 'Handling CanCan::AccessDenied', link: '/handling_access_denied' },
+ { text: 'Customize controller helpers', link: '/changing_defaults' },
+ { text: 'Accessing request data', link: '/accessing_request_data' },
+ { text: 'SQL strategies', link: '/sql_strategies' },
+ { text: 'Accessible attributes', link: '/accessible_attributes' },
+ { text: 'Testing', link: '/testing' },
+ { text: 'Internationalization', link: '/internationalization' }
+ ]
+ },
+ {
+ text: 'Further topics',
+ items: [
+ { text: 'Migrating', link: '/migrating' },
+ { text: 'Debugging Abilities', link: '/debugging' },
+ { text: 'Split your ability file', link: '/split_ability' },
+ { text: 'Define Abilities - best practices', link: '/define_abilities_best_practices' },
+ { text: 'Abilities in database', link: '/abilities_in_database' },
+ { text: 'Role-based Authorization', link: '/role_based_authorization' },
+ { text: 'Model Adapter', link: '/model_adapter' },
+ { text: 'Rules compression', link: '/rules_compression' },
+ { text: 'Inherited Resources', link: '/inherited_resources' },
+ { text: 'Devise', link: '/devise' },
+ { text: 'FriendlyId', link: '/friendly_id' }
+ ]
+ }
+ ],
+ socialLinks: [
+ { icon: 'github', link: 'https://github.com/CanCanCommunity/cancancan' }
+ ]
+ }
+})
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
new file mode 100644
index 000000000..8462969be
--- /dev/null
+++ b/docs/.vitepress/theme/index.ts
@@ -0,0 +1,16 @@
+// https://vitepress.dev/guide/custom-theme
+import { h } from 'vue'
+import type { Theme } from 'vitepress'
+import DefaultTheme from 'vitepress/theme'
+import './style.css'
+
+export default {
+ extends: DefaultTheme,
+ Layout: () => {
+ return h(DefaultTheme.Layout, null, {
+ // https://vitepress.dev/guide/extending-default-theme#layout-slots
+ })
+ },
+ enhanceApp({ app, router, siteData }) {
+ }
+} satisfies Theme
diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css
new file mode 100644
index 000000000..460b168b0
--- /dev/null
+++ b/docs/.vitepress/theme/style.css
@@ -0,0 +1,136 @@
+/**
+ * Customize default theme styling by overriding CSS variables:
+ * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
+ */
+
+/**
+ * Colors
+ *
+ * Each colors have exact same color scale system with 3 levels of solid
+ * colors with different brightness, and 1 soft color.
+ *
+ * - `XXX-1`: The most solid color used mainly for colored text. It must
+ * satisfy the contrast ratio against when used on top of `XXX-soft`.
+ *
+ * - `XXX-2`: The color used mainly for hover state of the button.
+ *
+ * - `XXX-3`: The color for solid background, such as bg color of the button.
+ * It must satisfy the contrast ratio with pure white (#ffffff) text on
+ * top of it.
+ *
+ * - `XXX-soft`: The color used for subtle background such as custom container
+ * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
+ * on top of it.
+ *
+ * The soft color must be semi transparent alpha channel. This is crucial
+ * because it allows adding multiple "soft" colors on top of each other
+ * to create a accent, such as when having inline code block inside
+ * custom containers.
+ *
+ * - `default`: The color used purely for subtle indication without any
+ * special meanings attched to it such as bg color for menu hover state.
+ *
+ * - `brand`: Used for primary brand colors, such as link text, button with
+ * brand theme, etc.
+ *
+ * - `tip`: Used to indicate useful information. The default theme uses the
+ * brand color for this by default.
+ *
+ * - `warning`: Used to indicate warning to the users. Used in custom
+ * container, badges, etc.
+ *
+ * - `danger`: Used to show error, or dangerous message to the users. Used
+ * in custom container, badges, etc.
+ * -------------------------------------------------------------------------- */
+
+ :root {
+ --vp-c-default-1: var(--vp-c-gray-1);
+ --vp-c-default-2: var(--vp-c-gray-2);
+ --vp-c-default-3: var(--vp-c-gray-3);
+ --vp-c-default-soft: var(--vp-c-gray-soft);
+
+ --vp-c-brand-1: var(--vp-c-indigo-1);
+ --vp-c-brand-2: var(--vp-c-indigo-2);
+ --vp-c-brand-3: var(--vp-c-indigo-3);
+ --vp-c-brand-soft: var(--vp-c-indigo-soft);
+
+ --vp-c-tip-1: var(--vp-c-brand-1);
+ --vp-c-tip-2: var(--vp-c-brand-2);
+ --vp-c-tip-3: var(--vp-c-brand-3);
+ --vp-c-tip-soft: var(--vp-c-brand-soft);
+
+ --vp-c-warning-1: var(--vp-c-yellow-1);
+ --vp-c-warning-2: var(--vp-c-yellow-2);
+ --vp-c-warning-3: var(--vp-c-yellow-3);
+ --vp-c-warning-soft: var(--vp-c-yellow-soft);
+
+ --vp-c-danger-1: var(--vp-c-red-1);
+ --vp-c-danger-2: var(--vp-c-red-2);
+ --vp-c-danger-3: var(--vp-c-red-3);
+ --vp-c-danger-soft: var(--vp-c-red-soft);
+}
+
+.dark .VPImage.logo {
+ filter: brightness(0) invert(1);
+}
+
+/**
+ * Component: Button
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-button-brand-border: transparent;
+ --vp-button-brand-text: var(--vp-c-white);
+ --vp-button-brand-bg: var(--vp-c-brand-3);
+ --vp-button-brand-hover-border: transparent;
+ --vp-button-brand-hover-text: var(--vp-c-white);
+ --vp-button-brand-hover-bg: var(--vp-c-brand-2);
+ --vp-button-brand-active-border: transparent;
+ --vp-button-brand-active-text: var(--vp-c-white);
+ --vp-button-brand-active-bg: var(--vp-c-brand-1);
+}
+
+/**
+ * Component: Home
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-home-hero-name-color: transparent;
+ --vp-home-hero-name-background: -webkit-linear-gradient(
+ 120deg,
+ #bd34fe 30%,
+ #41d1ff
+ );
+}
+
+@media (min-width: 640px) {
+ :root {
+ --vp-home-hero-image-filter: blur(56px);
+ }
+}
+
+@media (min-width: 960px) {
+ :root {
+ --vp-home-hero-image-filter: blur(68px);
+ }
+}
+
+/**
+ * Component: Custom Block
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-custom-block-tip-border: transparent;
+ --vp-custom-block-tip-text: var(--vp-c-text-1);
+ --vp-custom-block-tip-bg: var(--vp-c-brand-soft);
+ --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
+}
+
+/**
+ * Component: Algolia
+ * -------------------------------------------------------------------------- */
+
+.DocSearch {
+ --docsearch-primary-color: var(--vp-c-brand-1) !important;
+}
+
diff --git a/docs/check_abilities_mistakes.md b/docs/check_abilities_mistakes.md
index a9118eabb..1b8534808 100644
--- a/docs/check_abilities_mistakes.md
+++ b/docs/check_abilities_mistakes.md
@@ -14,7 +14,7 @@ cannot? :destroy, @article
What we want to explain you in this chapter is that you can also pass the class instead of a single instance:
-```rhtml
+```erb
<% if can? :create, Project %>
<%= link_to "New Project", new_project_path %>
<% end %>
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 000000000..cc22c9663
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,83 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+
+hero:
+ name: CanCanCan
+ text: Developer guide
+ tagline: The authorization Gem for Ruby on Rails.
+ image:
+ src: /cancancan.png
+ style:
+ # for dark mode
+ backgroundColor: '#fff'
+ borderRadius: '50%'
+ padding: '20px'
+ actions:
+ - theme: brand
+ text: Get Started
+ link: /README
+ - theme: alt
+ text: Installation
+ link: /installation
+ - theme: alt
+ text: GitHub
+ link: https://github.com/CanCanCommunity/cancancan
+
+features:
+ - title: "🔐 Secure Your Rails: CanCanCan's Authorization Mastery"
+ details: "Empowering developers to define and manage user permissions seamlessly."
+ - title: "🚀 Simplify with CanCanCan: Streamlined Permissions for Ruby"
+ details: "Dive into efficient, easy-to-manage access control for your Ruby applications."
+ - title: "✨ Permission Perfection with CanCanCan"
+ details: "Revolutionizing Ruby on Rails authorization with a unified, easy-to-use system."
+---
+
+## Our Sponsor
+
+
+
+
+
+_Do you want to sponsor CanCanCan and show your logo here? Check our [Sponsors Page](https://github.com/sponsors/coorasse)._
+
+## Questions?
+
+If you have any question or doubt regarding CanCanCan which you cannot find the solution to in the
+[documentation](./README.md), please
+[open a question on Stackoverflow](http://stackoverflow.com/questions/ask?tags=cancancan) with tag
+[cancancan](http://stackoverflow.com/questions/tagged/cancancan)
+
+## Bugs?
+
+If you find a bug please add an [issue on GitHub](https://github.com/CanCanCommunity/cancancan/issues) or fork the project and send a pull request.
+
+## Special Thanks
+
+Thanks to our Sponsors and to all the [CanCanCan contributors](https://github.com/CanCanCommunity/cancancan/contributors).
+See the [CHANGELOG](https://github.com/CanCanCommunity/cancancan/blob/main/CHANGELOG.md) for the full list.
diff --git a/docs/introduction.md b/docs/introduction.md
index 74ee76121..76693ec10 100644
--- a/docs/introduction.md
+++ b/docs/introduction.md
@@ -26,6 +26,23 @@ If you'd like to sponsor this library, head to
Head to the [Installation](./installation.md) chapter.
+
+
diff --git a/docs/model_adapter.md b/docs/model_adapter.md
index 0ebd36afc..6bed31694 100644
--- a/docs/model_adapter.md
+++ b/docs/model_adapter.md
@@ -195,15 +195,15 @@ Thus you'd probably be best served with inspecting the actual implementation of
#### Implementation
-- [ActiveRecord Base](../lib/cancan/model_adapters/active_record_adapter.rb)
-- [ActiveRecord 4](../lib/cancan/model_adapters/active_record_4_adapter.rb)
-- [ActiveRecord 5](../lib/cancan/model_adapters/active_record_5_adapter.rb)
+- [ActiveRecord Base](https://github.com/CanCanCommunity/cancancan/blob/develop/lib/cancan/model_adapters/active_record_adapter.rb)
+- [ActiveRecord 4](https://github.com/CanCanCommunity/cancancan/blob/develop/lib/cancan/model_adapters/active_record_4_adapter.rb)
+- [ActiveRecord 5](https://github.com/CanCanCommunity/cancancan/blob/develop/lib/cancan/model_adapters/active_record_5_adapter.rb)
#### Tests / Specs
-- [ActiveRecord Base](../spec/cancan/model_adapters/active_record_adapter_spec.rb)
-- [ActiveRecord 4](../spec/cancan/model_adapters/active_record_4_adapter_spec.rb)
-- [ActiveRecord 5](../spec/cancan/model_adapters/active_record_5_adapter_spec.rb)
+- [ActiveRecord Base](https://github.com/CanCanCommunity/cancancan/blob/develop/spec/cancan/model_adapters/active_record_adapter_spec.rb)
+- [ActiveRecord 4](https://github.com/CanCanCommunity/cancancan/blob/develop/spec/cancan/model_adapters/active_record_4_adapter_spec.rb)
+- [ActiveRecord 5](https://github.com/CanCanCommunity/cancancan/blob/develop/spec/cancan/model_adapters/active_record_5_adapter_spec.rb)
**Mongoid, the adapter used in this entry as an example, can be found at:**
diff --git a/docs/public/apple-touch-icon.png b/docs/public/apple-touch-icon.png
new file mode 100644
index 000000000..7fd00e20d
Binary files /dev/null and b/docs/public/apple-touch-icon.png differ
diff --git a/docs/public/cancancan.png b/docs/public/cancancan.png
new file mode 100755
index 000000000..11f168710
Binary files /dev/null and b/docs/public/cancancan.png differ
diff --git a/docs/public/favicon-16x16.png b/docs/public/favicon-16x16.png
new file mode 100644
index 000000000..4366c7924
Binary files /dev/null and b/docs/public/favicon-16x16.png differ
diff --git a/docs/public/favicon-32x32.png b/docs/public/favicon-32x32.png
new file mode 100644
index 000000000..95343a11d
Binary files /dev/null and b/docs/public/favicon-32x32.png differ
diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico
new file mode 100644
index 000000000..09d71b4f0
Binary files /dev/null and b/docs/public/favicon.ico differ
diff --git a/docs/public/goboony.png b/docs/public/goboony.png
new file mode 100644
index 000000000..7d77a4782
Binary files /dev/null and b/docs/public/goboony.png differ
diff --git a/docs/public/honeybadger.svg b/docs/public/honeybadger.svg
new file mode 100644
index 000000000..7d0531674
--- /dev/null
+++ b/docs/public/honeybadger.svg
@@ -0,0 +1,28 @@
+
+
+
diff --git a/docs/public/mstile-150x150.png b/docs/public/mstile-150x150.png
new file mode 100644
index 000000000..ecf34ed48
Binary files /dev/null and b/docs/public/mstile-150x150.png differ
diff --git a/docs/public/pennylane.svg b/docs/public/pennylane.svg
new file mode 100644
index 000000000..eeb8e8fe4
--- /dev/null
+++ b/docs/public/pennylane.svg
@@ -0,0 +1,6 @@
+
diff --git a/docs/public/renuo.png b/docs/public/renuo.png
new file mode 100644
index 000000000..0ce669dc6
Binary files /dev/null and b/docs/public/renuo.png differ
diff --git a/docs/public/safari-pinned-tab.svg b/docs/public/safari-pinned-tab.svg
new file mode 100644
index 000000000..2a38913c0
--- /dev/null
+++ b/docs/public/safari-pinned-tab.svg
@@ -0,0 +1,70 @@
+
+
+
diff --git a/docs/role_based_authorization.md b/docs/role_based_authorization.md
index b83f030df..6e45e2349 100644
--- a/docs/role_based_authorization.md
+++ b/docs/role_based_authorization.md
@@ -39,7 +39,7 @@ If you're using ActiveAdmin don't forget to add `role` to the `user.rb` list of
Now you can provide a select-menu for choosing the roles in the view.
-```rhtml
+```erb
<%= f.collection_select(:role, User::ROLES, :to_s, lambda{|i| i.to_s.humanize}) %>
```
@@ -89,7 +89,7 @@ If you're using devise, don't forget to add `attr_accessible :roles` to your use
You can use checkboxes in the view for setting these roles.
-```rhtml
+```erb
<% for role in User::ROLES %>
<%= check_box_tag "user[roles][#{role}]", role, @user.roles.include?(role), {:name => "user[roles][]"}%>
<%= label_tag "user_roles_#{role}", role.to_s.humanize %>
diff --git a/gemfiles/activerecord_5.1.0.gemfile b/gemfiles/activerecord_5.1.0.gemfile
deleted file mode 100644
index fe5514f1a..000000000
--- a/gemfiles/activerecord_5.1.0.gemfile
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was generated by Appraisal
-
-source "https://rubygems.org"
-
-gem "activerecord", "~> 5.1.0", require: "active_record"
-gem "activesupport", "~> 5.1.0", require: "active_support/all"
-gem "actionpack", "~> 5.1.0", require: "action_pack"
-
-platforms :jruby do
- gem "activerecord-jdbcsqlite3-adapter"
- gem "jdbc-sqlite3"
- gem "jdbc-postgres"
-end
-
-platforms :ruby, :mswin, :mingw do
- gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.4.2"
-end
-
-gemspec path: "../"
diff --git a/gemfiles/activerecord_5.2.2.gemfile b/gemfiles/activerecord_5.2.2.gemfile
index 63ce61b4e..071167d7e 100644
--- a/gemfiles/activerecord_5.2.2.gemfile
+++ b/gemfiles/activerecord_5.2.2.gemfile
@@ -14,7 +14,7 @@ end
platforms :ruby, :mswin, :mingw do
gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.4.2"
+ gem "sqlite3", "~> 1.7.3"
end
gemspec path: "../"
diff --git a/gemfiles/activerecord_6.0.0.gemfile b/gemfiles/activerecord_6.0.0.gemfile
index e9f11ddd0..a2777cd19 100644
--- a/gemfiles/activerecord_6.0.0.gemfile
+++ b/gemfiles/activerecord_6.0.0.gemfile
@@ -14,7 +14,7 @@ end
platforms :ruby, :mswin, :mingw do
gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.4.2"
+ gem "sqlite3", "~> 1.7.3"
end
gemspec path: "../"
diff --git a/gemfiles/activerecord_6.1.0.gemfile b/gemfiles/activerecord_6.1.0.gemfile
index 88580ffa1..fd081871c 100644
--- a/gemfiles/activerecord_6.1.0.gemfile
+++ b/gemfiles/activerecord_6.1.0.gemfile
@@ -14,7 +14,7 @@ end
platforms :ruby, :mswin, :mingw do
gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.4.2"
+ gem "sqlite3", "~> 1.7.3"
end
gemspec path: "../"
diff --git a/gemfiles/activerecord_7.0.0.gemfile b/gemfiles/activerecord_7.0.0.gemfile
index 1f0c169dd..c0840521c 100644
--- a/gemfiles/activerecord_7.0.0.gemfile
+++ b/gemfiles/activerecord_7.0.0.gemfile
@@ -14,7 +14,7 @@ end
platforms :ruby, :mswin, :mingw do
gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.4.2"
+ gem "sqlite3", "~> 1.7.3"
end
gemspec path: "../"
diff --git a/gemfiles/activerecord_5.0.2.gemfile b/gemfiles/activerecord_7.1.0.gemfile
similarity index 51%
rename from gemfiles/activerecord_5.0.2.gemfile
rename to gemfiles/activerecord_7.1.0.gemfile
index 8f0cb561a..72952c7b5 100644
--- a/gemfiles/activerecord_5.0.2.gemfile
+++ b/gemfiles/activerecord_7.1.0.gemfile
@@ -2,9 +2,9 @@
source "https://rubygems.org"
-gem "activerecord", "~> 5.0.2", require: "active_record"
-gem "activesupport", "~> 5.0.2", require: "active_support/all"
-gem "actionpack", "~> 5.0.2", require: "action_pack"
+gem "actionpack", "~> 7.1.0", require: "action_pack"
+gem "activerecord", "~> 7.1.0", require: "active_record"
+gem "activesupport", "~> 7.1.0", require: "active_support/all"
platforms :jruby do
gem "activerecord-jdbcsqlite3-adapter"
@@ -13,8 +13,8 @@ platforms :jruby do
end
platforms :ruby, :mswin, :mingw do
- gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.3.0"
+ gem "pg", "~> 1.5.6"
+ gem "sqlite3", "~> 1.7.3"
end
gemspec path: "../"
diff --git a/gemfiles/activerecord_main.gemfile b/gemfiles/activerecord_main.gemfile
index ba43821e8..cbc6172ca 100644
--- a/gemfiles/activerecord_main.gemfile
+++ b/gemfiles/activerecord_main.gemfile
@@ -15,8 +15,8 @@ platforms :jruby do
end
platforms :ruby, :mswin, :mingw do
- gem "pg", "~> 1.3.4"
- gem "sqlite3", "~> 1.4.2"
+ gem "pg", "~> 1.5.6"
+ gem "sqlite3", "~> 1.7.3"
end
gemspec path: "../"
diff --git a/lib/cancan/model_adapters/active_record_adapter.rb b/lib/cancan/model_adapters/active_record_adapter.rb
index 6d17f8634..33766c0a4 100644
--- a/lib/cancan/model_adapters/active_record_adapter.rb
+++ b/lib/cancan/model_adapters/active_record_adapter.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# rubocop:disable Metrics/AbcSize
+# rubocop:disable Metrics/CyclomaticComplexity
+# rubocop:disable Metrics/PerceivedComplexity
module CanCan
module ModelAdapters
class ActiveRecordAdapter < AbstractAdapter
@@ -52,7 +55,7 @@ def parent_child_conditions(parent, child, all_conditions)
# Search again in case of polymorphic associations, this time matching on the :has_many side
# via the :as option, as well as klass
foreign_key ||= parent_class.reflect_on_all_associations(:has_many).find do |has_many_assoc|
- !matching_parent_child_polymorphic_association(has_many_assoc, child_class).nil?
+ matching_parent_child_polymorphic_association(has_many_assoc, child_class)
end&.foreign_key&.to_sym
foreign_key.nil? ? nil : all_conditions[foreign_key]
@@ -61,7 +64,7 @@ def parent_child_conditions(parent, child, all_conditions)
def matching_parent_child_polymorphic_association(parent_assoc, child_class)
return nil unless parent_assoc.klass == child_class
return nil if parent_assoc&.options[:as].nil?
-
+
child_class.reflect_on_all_associations(:belongs_to).find do |child_assoc|
# Only match this way for polymorphic associations
child_assoc.polymorphic? && child_assoc.name == parent_assoc.options[:as]
@@ -72,12 +75,12 @@ def child_association_to_parent(parent, child)
child_class = child.is_a?(Class) ? child : child.class
parent_class = parent.is_a?(Class) ? parent : parent.class
- association = child_class.reflect_on_all_associations(:belongs_to).find do |association|
+ association = child_class.reflect_on_all_associations(:belongs_to).find do |belongs_to_assoc|
# Do not match on polymorphic associations or it will throw an error (klass cannot be determined)
- !association.polymorphic? && association.klass == parent.class
+ !belongs_to_assoc.polymorphic? && belongs_to_assoc.klass == parent.class
end
- return association unless association.nil?
+ return association if association
parent_class.reflect_on_all_associations(:has_many).each do |has_many_assoc|
association ||= matching_parent_child_polymorphic_association(has_many_assoc, child_class)
@@ -217,6 +220,9 @@ def sanitize_sql(conditions)
end
end
end
+# rubocop:enable Metrics/PerceivedComplexity
+# rubocop:enable Metrics/CyclomaticComplexity
+# rubocop:enable Metrics/AbcSize
ActiveSupport.on_load(:active_record) do
send :include, CanCan::ModelAdditions
diff --git a/lib/cancan/rules_compressor.rb b/lib/cancan/rules_compressor.rb
index 01b9e325d..46f5a4cbc 100644
--- a/lib/cancan/rules_compressor.rb
+++ b/lib/cancan/rules_compressor.rb
@@ -11,6 +11,7 @@ def initialize(rules)
end
def compress(array)
+ array = simplify(array)
idx = array.rindex(&:catch_all?)
return array unless idx
@@ -19,5 +20,22 @@ def compress(array)
.drop_while { |n| n.base_behavior == value.base_behavior }
.tap { |a| a.unshift(value) unless value.cannot_catch_all? }
end
+
+ # If we have A OR (!A AND anything ), then we can simplify to A OR anything
+ # If we have A OR (A OR anything ), then we can simplify to A OR anything
+ # If we have !A AND (A OR something), then we can simplify it to !A AND something
+ # If we have !A AND (!A AND something), then we can simplify it to !A AND something
+ #
+ # So as soon as we see a condition that is the same as the previous one,
+ # we can skip it, no matter of the base_behavior
+ def simplify(rules)
+ seen = Set.new
+ rules.reverse_each.filter_map do |rule|
+ next if seen.include?(rule.conditions)
+
+ seen.add(rule.conditions)
+ rule
+ end.reverse
+ end
end
end
diff --git a/lib/cancan/version.rb b/lib/cancan/version.rb
index 7477402a8..476bcd8ac 100644
--- a/lib/cancan/version.rb
+++ b/lib/cancan/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module CanCan
- VERSION = '3.5.0'.freeze
+ VERSION = '3.6.0'.freeze
end
diff --git a/logo/bullet_train.png b/logo/bullet_train.png
deleted file mode 100644
index 0e40a801d..000000000
Binary files a/logo/bullet_train.png and /dev/null differ
diff --git a/logo/modern_treasury.svg b/logo/modern_treasury.svg
deleted file mode 100644
index 8a15c495a..000000000
--- a/logo/modern_treasury.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
diff --git a/logo/new_relic.png b/logo/new_relic.png
deleted file mode 100644
index 6b9f27c11..000000000
Binary files a/logo/new_relic.png and /dev/null differ
diff --git a/logo/ontra.png b/logo/ontra.png
deleted file mode 100644
index e7f243b70..000000000
Binary files a/logo/ontra.png and /dev/null differ
diff --git a/logo/pennylane.svg b/logo/pennylane.svg
new file mode 100644
index 000000000..eeb8e8fe4
--- /dev/null
+++ b/logo/pennylane.svg
@@ -0,0 +1,6 @@
+
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..2deac3c0f
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1510 @@
+{
+ "name": "cancancan",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "vitepress": "^1.2.2"
+ }
+ },
+ "node_modules/@algolia/autocomplete-core": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz",
+ "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==",
+ "dependencies": {
+ "@algolia/autocomplete-plugin-algolia-insights": "1.9.3",
+ "@algolia/autocomplete-shared": "1.9.3"
+ }
+ },
+ "node_modules/@algolia/autocomplete-plugin-algolia-insights": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz",
+ "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==",
+ "dependencies": {
+ "@algolia/autocomplete-shared": "1.9.3"
+ },
+ "peerDependencies": {
+ "search-insights": ">= 1 < 3"
+ }
+ },
+ "node_modules/@algolia/autocomplete-preset-algolia": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz",
+ "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==",
+ "dependencies": {
+ "@algolia/autocomplete-shared": "1.9.3"
+ },
+ "peerDependencies": {
+ "@algolia/client-search": ">= 4.9.1 < 6",
+ "algoliasearch": ">= 4.9.1 < 6"
+ }
+ },
+ "node_modules/@algolia/autocomplete-shared": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz",
+ "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==",
+ "peerDependencies": {
+ "@algolia/client-search": ">= 4.9.1 < 6",
+ "algoliasearch": ">= 4.9.1 < 6"
+ }
+ },
+ "node_modules/@algolia/cache-browser-local-storage": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.23.3.tgz",
+ "integrity": "sha512-vRHXYCpPlTDE7i6UOy2xE03zHF2C8MEFjPN2v7fRbqVpcOvAUQK81x3Kc21xyb5aSIpYCjWCZbYZuz8Glyzyyg==",
+ "dependencies": {
+ "@algolia/cache-common": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/cache-common": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.23.3.tgz",
+ "integrity": "sha512-h9XcNI6lxYStaw32pHpB1TMm0RuxphF+Ik4o7tcQiodEdpKK+wKufY6QXtba7t3k8eseirEMVB83uFFF3Nu54A=="
+ },
+ "node_modules/@algolia/cache-in-memory": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.23.3.tgz",
+ "integrity": "sha512-yvpbuUXg/+0rbcagxNT7un0eo3czx2Uf0y4eiR4z4SD7SiptwYTpbuS0IHxcLHG3lq22ukx1T6Kjtk/rT+mqNg==",
+ "dependencies": {
+ "@algolia/cache-common": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/client-account": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.23.3.tgz",
+ "integrity": "sha512-hpa6S5d7iQmretHHF40QGq6hz0anWEHGlULcTIT9tbUssWUriN9AUXIFQ8Ei4w9azD0hc1rUok9/DeQQobhQMA==",
+ "dependencies": {
+ "@algolia/client-common": "4.23.3",
+ "@algolia/client-search": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/client-analytics": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.23.3.tgz",
+ "integrity": "sha512-LBsEARGS9cj8VkTAVEZphjxTjMVCci+zIIiRhpFun9jGDUlS1XmhCW7CTrnaWeIuCQS/2iPyRqSy1nXPjcBLRA==",
+ "dependencies": {
+ "@algolia/client-common": "4.23.3",
+ "@algolia/client-search": "4.23.3",
+ "@algolia/requester-common": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/client-common": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.23.3.tgz",
+ "integrity": "sha512-l6EiPxdAlg8CYhroqS5ybfIczsGUIAC47slLPOMDeKSVXYG1n0qGiz4RjAHLw2aD0xzh2EXZ7aRguPfz7UKDKw==",
+ "dependencies": {
+ "@algolia/requester-common": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/client-personalization": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.23.3.tgz",
+ "integrity": "sha512-3E3yF3Ocr1tB/xOZiuC3doHQBQ2zu2MPTYZ0d4lpfWads2WTKG7ZzmGnsHmm63RflvDeLK/UVx7j2b3QuwKQ2g==",
+ "dependencies": {
+ "@algolia/client-common": "4.23.3",
+ "@algolia/requester-common": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/client-search": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.23.3.tgz",
+ "integrity": "sha512-P4VAKFHqU0wx9O+q29Q8YVuaowaZ5EM77rxfmGnkHUJggh28useXQdopokgwMeYw2XUht49WX5RcTQ40rZIabw==",
+ "dependencies": {
+ "@algolia/client-common": "4.23.3",
+ "@algolia/requester-common": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/logger-common": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.23.3.tgz",
+ "integrity": "sha512-y9kBtmJwiZ9ZZ+1Ek66P0M68mHQzKRxkW5kAAXYN/rdzgDN0d2COsViEFufxJ0pb45K4FRcfC7+33YB4BLrZ+g=="
+ },
+ "node_modules/@algolia/logger-console": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.23.3.tgz",
+ "integrity": "sha512-8xoiseoWDKuCVnWP8jHthgaeobDLolh00KJAdMe9XPrWPuf1by732jSpgy2BlsLTaT9m32pHI8CRfrOqQzHv3A==",
+ "dependencies": {
+ "@algolia/logger-common": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/recommend": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.23.3.tgz",
+ "integrity": "sha512-9fK4nXZF0bFkdcLBRDexsnGzVmu4TSYZqxdpgBW2tEyfuSSY54D4qSRkLmNkrrz4YFvdh2GM1gA8vSsnZPR73w==",
+ "dependencies": {
+ "@algolia/cache-browser-local-storage": "4.23.3",
+ "@algolia/cache-common": "4.23.3",
+ "@algolia/cache-in-memory": "4.23.3",
+ "@algolia/client-common": "4.23.3",
+ "@algolia/client-search": "4.23.3",
+ "@algolia/logger-common": "4.23.3",
+ "@algolia/logger-console": "4.23.3",
+ "@algolia/requester-browser-xhr": "4.23.3",
+ "@algolia/requester-common": "4.23.3",
+ "@algolia/requester-node-http": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/requester-browser-xhr": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.3.tgz",
+ "integrity": "sha512-jDWGIQ96BhXbmONAQsasIpTYWslyjkiGu0Quydjlowe+ciqySpiDUrJHERIRfELE5+wFc7hc1Q5hqjGoV7yghw==",
+ "dependencies": {
+ "@algolia/requester-common": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/requester-common": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.23.3.tgz",
+ "integrity": "sha512-xloIdr/bedtYEGcXCiF2muajyvRhwop4cMZo+K2qzNht0CMzlRkm8YsDdj5IaBhshqfgmBb3rTg4sL4/PpvLYw=="
+ },
+ "node_modules/@algolia/requester-node-http": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.23.3.tgz",
+ "integrity": "sha512-zgu++8Uj03IWDEJM3fuNl34s746JnZOWn1Uz5taV1dFyJhVM/kTNw9Ik7YJWiUNHJQXcaD8IXD1eCb0nq/aByA==",
+ "dependencies": {
+ "@algolia/requester-common": "4.23.3"
+ }
+ },
+ "node_modules/@algolia/transporter": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.23.3.tgz",
+ "integrity": "sha512-Wjl5gttqnf/gQKJA+dafnD0Y6Yw97yvfY8R9h0dQltX1GXTgNs1zWgvtWW0tHl1EgMdhAyw189uWiZMnL3QebQ==",
+ "dependencies": {
+ "@algolia/cache-common": "4.23.3",
+ "@algolia/logger-common": "4.23.3",
+ "@algolia/requester-common": "4.23.3"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
+ "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@docsearch/css": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.0.tgz",
+ "integrity": "sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ=="
+ },
+ "node_modules/@docsearch/js": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.6.0.tgz",
+ "integrity": "sha512-QujhqINEElrkIfKwyyyTfbsfMAYCkylInLYMRqHy7PHc8xTBQCow73tlo/Kc7oIwBrCLf0P3YhjlOeV4v8hevQ==",
+ "dependencies": {
+ "@docsearch/react": "3.6.0",
+ "preact": "^10.0.0"
+ }
+ },
+ "node_modules/@docsearch/react": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.0.tgz",
+ "integrity": "sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==",
+ "dependencies": {
+ "@algolia/autocomplete-core": "1.9.3",
+ "@algolia/autocomplete-preset-algolia": "1.9.3",
+ "@docsearch/css": "3.6.0",
+ "algoliasearch": "^4.19.1"
+ },
+ "peerDependencies": {
+ "@types/react": ">= 16.8.0 < 19.0.0",
+ "react": ">= 16.8.0 < 19.0.0",
+ "react-dom": ">= 16.8.0 < 19.0.0",
+ "search-insights": ">= 1 < 3"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "search-insights": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
+ "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
+ "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
+ "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
+ "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
+ "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
+ "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
+ "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
+ "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
+ "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
+ "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
+ "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
+ "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
+ "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
+ "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
+ "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
+ "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
+ "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
+ "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
+ "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
+ "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
+ "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
+ "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
+ "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
+ "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz",
+ "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz",
+ "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz",
+ "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz",
+ "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz",
+ "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz",
+ "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz",
+ "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz",
+ "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz",
+ "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz",
+ "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz",
+ "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz",
+ "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz",
+ "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz",
+ "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz",
+ "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@shikijs/core": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.6.0.tgz",
+ "integrity": "sha512-NIEAi5U5R7BLkbW1pG/ZKu3eb1lzc3/+jD0lFsuxMT7zjaf9bbNwdNyMr7zh/Zl8EXQtQ+MYBAt5G+JLu+5DlA=="
+ },
+ "node_modules/@shikijs/transformers": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.6.0.tgz",
+ "integrity": "sha512-qGfHe1ECiqfE2STPWvfogIj/9Q0SK+MCRJdoITkW7AmFuB7DmbFnBT2US84+zklJOB51MzNO8RUXZiauWssJlQ==",
+ "dependencies": {
+ "shiki": "1.6.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
+ },
+ "node_modules/@types/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="
+ },
+ "node_modules/@types/markdown-it": {
+ "version": "14.1.1",
+ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz",
+ "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==",
+ "dependencies": {
+ "@types/linkify-it": "^5",
+ "@types/mdurl": "^2"
+ }
+ },
+ "node_modules/@types/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="
+ },
+ "node_modules/@types/web-bluetooth": {
+ "version": "0.0.20",
+ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
+ "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz",
+ "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.27.tgz",
+ "integrity": "sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==",
+ "dependencies": {
+ "@babel/parser": "^7.24.4",
+ "@vue/shared": "3.4.27",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz",
+ "integrity": "sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==",
+ "dependencies": {
+ "@vue/compiler-core": "3.4.27",
+ "@vue/shared": "3.4.27"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz",
+ "integrity": "sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==",
+ "dependencies": {
+ "@babel/parser": "^7.24.4",
+ "@vue/compiler-core": "3.4.27",
+ "@vue/compiler-dom": "3.4.27",
+ "@vue/compiler-ssr": "3.4.27",
+ "@vue/shared": "3.4.27",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.10",
+ "postcss": "^8.4.38",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz",
+ "integrity": "sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.4.27",
+ "@vue/shared": "3.4.27"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.2.1.tgz",
+ "integrity": "sha512-6oNCtyFOrNdqm6GUkFujsCgFlpbsHLnZqq7edeM/+cxAbMyCWvsaCsIMUaz7AiluKLccCGEM8fhOsjaKgBvb7g==",
+ "dependencies": {
+ "@vue/devtools-kit": "^7.2.1"
+ }
+ },
+ "node_modules/@vue/devtools-kit": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.2.1.tgz",
+ "integrity": "sha512-Wak/fin1X0Q8LLIfCAHBrdaaB+R6IdpSXsDByPHbQ3BmkCP0/cIo/oEGp9i0U2+gEqD4L3V9RDjNf1S34DTzQQ==",
+ "dependencies": {
+ "@vue/devtools-shared": "^7.2.1",
+ "hookable": "^5.5.3",
+ "mitt": "^3.0.1",
+ "perfect-debounce": "^1.0.0",
+ "speakingurl": "^14.0.1"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/@vue/devtools-shared": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.2.1.tgz",
+ "integrity": "sha512-PCJF4UknJmOal68+X9XHyVeQ+idv0LFujkTOIW30+GaMJqwFVN9LkQKX4gLqn61KkGMdJTzQ1bt7EJag3TI6AA==",
+ "dependencies": {
+ "rfdc": "^1.3.1"
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.27.tgz",
+ "integrity": "sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==",
+ "dependencies": {
+ "@vue/shared": "3.4.27"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.27.tgz",
+ "integrity": "sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==",
+ "dependencies": {
+ "@vue/reactivity": "3.4.27",
+ "@vue/shared": "3.4.27"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz",
+ "integrity": "sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==",
+ "dependencies": {
+ "@vue/runtime-core": "3.4.27",
+ "@vue/shared": "3.4.27",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.27.tgz",
+ "integrity": "sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.4.27",
+ "@vue/shared": "3.4.27"
+ },
+ "peerDependencies": {
+ "vue": "3.4.27"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.27.tgz",
+ "integrity": "sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA=="
+ },
+ "node_modules/@vueuse/core": {
+ "version": "10.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz",
+ "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.20",
+ "@vueuse/metadata": "10.9.0",
+ "@vueuse/shared": "10.9.0",
+ "vue-demi": ">=0.14.7"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/core/node_modules/vue-demi": {
+ "version": "0.14.7",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
+ "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
+ "hasInstallScript": true,
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vueuse/integrations": {
+ "version": "10.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-10.9.0.tgz",
+ "integrity": "sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==",
+ "dependencies": {
+ "@vueuse/core": "10.9.0",
+ "@vueuse/shared": "10.9.0",
+ "vue-demi": ">=0.14.7"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "async-validator": "*",
+ "axios": "*",
+ "change-case": "*",
+ "drauu": "*",
+ "focus-trap": "*",
+ "fuse.js": "*",
+ "idb-keyval": "*",
+ "jwt-decode": "*",
+ "nprogress": "*",
+ "qrcode": "*",
+ "sortablejs": "*",
+ "universal-cookie": "*"
+ },
+ "peerDependenciesMeta": {
+ "async-validator": {
+ "optional": true
+ },
+ "axios": {
+ "optional": true
+ },
+ "change-case": {
+ "optional": true
+ },
+ "drauu": {
+ "optional": true
+ },
+ "focus-trap": {
+ "optional": true
+ },
+ "fuse.js": {
+ "optional": true
+ },
+ "idb-keyval": {
+ "optional": true
+ },
+ "jwt-decode": {
+ "optional": true
+ },
+ "nprogress": {
+ "optional": true
+ },
+ "qrcode": {
+ "optional": true
+ },
+ "sortablejs": {
+ "optional": true
+ },
+ "universal-cookie": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vueuse/integrations/node_modules/vue-demi": {
+ "version": "0.14.7",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
+ "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
+ "hasInstallScript": true,
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vueuse/metadata": {
+ "version": "10.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz",
+ "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/shared": {
+ "version": "10.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz",
+ "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==",
+ "dependencies": {
+ "vue-demi": ">=0.14.7"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@vueuse/shared/node_modules/vue-demi": {
+ "version": "0.14.7",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
+ "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
+ "hasInstallScript": true,
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/algoliasearch": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.3.tgz",
+ "integrity": "sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg==",
+ "dependencies": {
+ "@algolia/cache-browser-local-storage": "4.23.3",
+ "@algolia/cache-common": "4.23.3",
+ "@algolia/cache-in-memory": "4.23.3",
+ "@algolia/client-account": "4.23.3",
+ "@algolia/client-analytics": "4.23.3",
+ "@algolia/client-common": "4.23.3",
+ "@algolia/client-personalization": "4.23.3",
+ "@algolia/client-search": "4.23.3",
+ "@algolia/logger-common": "4.23.3",
+ "@algolia/logger-console": "4.23.3",
+ "@algolia/recommend": "4.23.3",
+ "@algolia/requester-browser-xhr": "4.23.3",
+ "@algolia/requester-common": "4.23.3",
+ "@algolia/requester-node-http": "4.23.3",
+ "@algolia/transporter": "4.23.3"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
+ "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.20.2",
+ "@esbuild/android-arm": "0.20.2",
+ "@esbuild/android-arm64": "0.20.2",
+ "@esbuild/android-x64": "0.20.2",
+ "@esbuild/darwin-arm64": "0.20.2",
+ "@esbuild/darwin-x64": "0.20.2",
+ "@esbuild/freebsd-arm64": "0.20.2",
+ "@esbuild/freebsd-x64": "0.20.2",
+ "@esbuild/linux-arm": "0.20.2",
+ "@esbuild/linux-arm64": "0.20.2",
+ "@esbuild/linux-ia32": "0.20.2",
+ "@esbuild/linux-loong64": "0.20.2",
+ "@esbuild/linux-mips64el": "0.20.2",
+ "@esbuild/linux-ppc64": "0.20.2",
+ "@esbuild/linux-riscv64": "0.20.2",
+ "@esbuild/linux-s390x": "0.20.2",
+ "@esbuild/linux-x64": "0.20.2",
+ "@esbuild/netbsd-x64": "0.20.2",
+ "@esbuild/openbsd-x64": "0.20.2",
+ "@esbuild/sunos-x64": "0.20.2",
+ "@esbuild/win32-arm64": "0.20.2",
+ "@esbuild/win32-ia32": "0.20.2",
+ "@esbuild/win32-x64": "0.20.2"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "node_modules/focus-trap": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz",
+ "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==",
+ "dependencies": {
+ "tabbable": "^6.2.0"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/hookable": {
+ "version": "5.5.3",
+ "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.10",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
+ "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ }
+ },
+ "node_modules/mark.js": {
+ "version": "8.11.1",
+ "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz",
+ "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="
+ },
+ "node_modules/minisearch": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-6.3.0.tgz",
+ "integrity": "sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ=="
+ },
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/perfect-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ },
+ "node_modules/postcss": {
+ "version": "8.4.38",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+ "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.2.0"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/preact": {
+ "version": "10.22.0",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.22.0.tgz",
+ "integrity": "sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/rfdc": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz",
+ "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg=="
+ },
+ "node_modules/rollup": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz",
+ "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==",
+ "dependencies": {
+ "@types/estree": "1.0.5"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.18.0",
+ "@rollup/rollup-android-arm64": "4.18.0",
+ "@rollup/rollup-darwin-arm64": "4.18.0",
+ "@rollup/rollup-darwin-x64": "4.18.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.18.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.18.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.18.0",
+ "@rollup/rollup-linux-arm64-musl": "4.18.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.18.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.18.0",
+ "@rollup/rollup-linux-x64-gnu": "4.18.0",
+ "@rollup/rollup-linux-x64-musl": "4.18.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.18.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.18.0",
+ "@rollup/rollup-win32-x64-msvc": "4.18.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/search-insights": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.14.0.tgz",
+ "integrity": "sha512-OLN6MsPMCghDOqlCtsIsYgtsC0pnwVTyT9Mu6A3ewOj1DxvzZF6COrn2g86E/c05xbktB0XN04m/t1Z+n+fTGw==",
+ "peer": true
+ },
+ "node_modules/shiki": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.6.0.tgz",
+ "integrity": "sha512-P31ROeXcVgW/k3Z+vUUErcxoTah7ZRaimctOpzGuqAntqnnSmx1HOsvnbAB8Z2qfXPRhw61yptAzCsuKOhTHwQ==",
+ "dependencies": {
+ "@shikijs/core": "1.6.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/speakingurl": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
+ "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tabbable": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
+ "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
+ },
+ "node_modules/vite": {
+ "version": "5.2.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
+ "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==",
+ "dependencies": {
+ "esbuild": "^0.20.1",
+ "postcss": "^8.4.38",
+ "rollup": "^4.13.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitepress": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.2.2.tgz",
+ "integrity": "sha512-uZ3nXR5NY4nYj3RJWCo5jev9qlNZAQo5SUXu1U0QSUx84cUm/o7hCTDVjZ4njVSVui+PsV1oAbdQOg8ygbaf4w==",
+ "dependencies": {
+ "@docsearch/css": "^3.6.0",
+ "@docsearch/js": "^3.6.0",
+ "@shikijs/core": "^1.5.2",
+ "@shikijs/transformers": "^1.5.2",
+ "@types/markdown-it": "^14.1.1",
+ "@vitejs/plugin-vue": "^5.0.4",
+ "@vue/devtools-api": "^7.2.0",
+ "@vue/shared": "^3.4.27",
+ "@vueuse/core": "^10.9.0",
+ "@vueuse/integrations": "^10.9.0",
+ "focus-trap": "^7.5.4",
+ "mark.js": "8.11.1",
+ "minisearch": "^6.3.0",
+ "shiki": "^1.5.2",
+ "vite": "^5.2.11",
+ "vue": "^3.4.27"
+ },
+ "bin": {
+ "vitepress": "bin/vitepress.js"
+ },
+ "peerDependencies": {
+ "markdown-it-mathjax3": "^4",
+ "postcss": "^8"
+ },
+ "peerDependenciesMeta": {
+ "markdown-it-mathjax3": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue": {
+ "version": "3.4.27",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.27.tgz",
+ "integrity": "sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.4.27",
+ "@vue/compiler-sfc": "3.4.27",
+ "@vue/runtime-dom": "3.4.27",
+ "@vue/server-renderer": "3.4.27",
+ "@vue/shared": "3.4.27"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..32f82dffc
--- /dev/null
+++ b/package.json
@@ -0,0 +1,10 @@
+{
+ "scripts": {
+ "docs:dev": "vitepress dev docs",
+ "docs:build": "vitepress build docs",
+ "docs:preview": "vitepress preview docs"
+ },
+ "dependencies": {
+ "vitepress": "^1.2.2"
+ }
+}
diff --git a/spec/cancan/rule_compressor_spec.rb b/spec/cancan/rule_compressor_spec.rb
index 3f643ef24..a2e1d2953 100644
--- a/spec/cancan/rule_compressor_spec.rb
+++ b/spec/cancan/rule_compressor_spec.rb
@@ -87,8 +87,7 @@ def cannot(action, subject, args = nil)
end
end
- # TODO: not supported yet
- xcontext 'duplicate rules' do
+ context 'duplicate rules' do
let(:rules) do
[can(:read, Blog, id: 4),
can(:read, Blog, id: 1),
@@ -99,7 +98,42 @@ def cannot(action, subject, args = nil)
end
it 'minimizes the rules, by removing duplicates' do
- expect(described_class.new(rules).rules_collapsed).to eq [rules[0], rules[1], rules[2], rules[4]]
+ expect(described_class.new(rules).rules_collapsed).to eq [rules[0], rules[1], rules[4], rules[5]]
+ end
+ end
+
+ context 'duplicates rules with cannot' do
+ let(:rules) do
+ [can(:read, Blog, id: 1),
+ cannot(:read, Blog, id: 1)]
+ end
+
+ it 'minimizes the rules, by removing useless previous rules' do
+ expect(described_class.new(rules).rules_collapsed).to eq [rules[1]]
+ end
+ end
+
+ context 'duplicates rules with cannot and can again' do
+ let(:rules) do
+ [can(:read, Blog, id: [1, 2]),
+ cannot(:read, Blog, id: 1),
+ can(:read, Blog, id: 1)]
+ end
+
+ it 'minimizes the rules, by removing useless previous rules' do
+ expect(described_class.new(rules).rules_collapsed).to eq [rules[0], rules[2]]
+ end
+ end
+
+ context 'duplicates rules with 2 cannot' do
+ let(:rules) do
+ [can(:read, Blog),
+ cannot(:read, Blog, id: 1),
+ cannot(:read, Blog, id: 1)]
+ end
+
+ it 'minimizes the rules, by removing useless previous rules' do
+ expect(described_class.new(rules).rules_collapsed).to eq [rules[0], rules[2]]
end
end