diff --git a/.claude/skills/github-issue-fixy/SKILL.md b/.claude/skills/github-issue-fixy/SKILL.md
new file mode 100644
index 00000000..b0e53f58
--- /dev/null
+++ b/.claude/skills/github-issue-fixy/SKILL.md
@@ -0,0 +1,309 @@
+---
+name: github-issue-solver
+description: Accept a GitHub issue URL or issue details, create a comprehensive plan (in plan mode - shows plan first), then implement the solution including tests and documentation, create/update release notes for Home Assistant users, and update the README roadmap for new features. Use when the user provides a GitHub issue or asks to solve an issue. ALWAYS presents the plan first and waits for user approval before implementing.
+---
+
+# GitHub Issue Solver
+
+This skill guides you through solving GitHub issues for the Home Assistant device-card project. It ensures comprehensive planning, testing, documentation, and release notes.
+
+## When to Use
+
+- Use this skill when the user provides a GitHub issue URL or issue details
+- Use when asked to solve, fix, or implement something from a GitHub issue
+- Use when planning work based on an issue or feature request
+
+## Instructions
+
+**IMPORTANT: This skill runs in PLAN MODE first. You MUST present a comprehensive plan to the user and wait for their approval before implementing any code changes.**
+
+### Step 1: Analyze the GitHub Issue
+
+1. **Fetch the issue details**:
+ - If a GitHub issue URL is provided, fetch it using the web fetch tool or ask the user for the issue details
+ - Extract key information:
+ - Issue title and description
+ - Issue type (bug fix, feature request, enhancement, etc.)
+ - Labels and milestones
+ - Comments and discussion
+ - Related issues or PRs
+
+2. **Understand the requirements**:
+ - Identify what needs to be fixed or implemented
+ - Note any edge cases or special considerations mentioned
+ - Check if there are any related issues or dependencies
+
+### Step 2: Create and Present the Plan (STOP HERE - DO NOT IMPLEMENT YET)
+
+1. **Break down the work**:
+ - List all files that need to be created or modified
+ - Identify the core functionality changes required
+ - Note any dependencies or related components
+ - Review existing code patterns in the project for consistency
+
+2. **Create a comprehensive task list**:
+ - Use the todo_write tool to create a structured task list with all tasks marked as "pending"
+ - Include detailed tasks for:
+ - Code implementation (specific files and functions)
+ - Test creation/updates (specific test files and test cases)
+ - Documentation updates (specific sections and files)
+ - Release notes (draft the entry)
+ - README roadmap update (if new feature, draft the entry)
+
+3. **Present the plan to the user**:
+ - **CRITICAL: You MUST stop here and present the complete plan**
+ - Show a clear, formatted plan including:
+ - Summary of the issue and what needs to be done
+ - List of files to be created/modified
+ - Overview of code changes needed
+ - Test strategy and test cases
+ - Documentation updates planned
+ - Draft release notes entry
+ - Draft roadmap entry (if new feature)
+ - **Wait for user approval before proceeding to Step 3**
+ - Use language like: "Here's my plan. Please review and let me know if you'd like me to proceed with implementation."
+
+### Step 3: Implement the Solution (ONLY AFTER USER APPROVAL)
+
+**DO NOT proceed to this step until the user has reviewed and approved the plan from Step 2.**
+
+1. **Code changes**:
+ - Follow TypeScript best practices
+ - Match the existing code style (check `.prettierrc` for formatting)
+ - Ensure type safety (check `tsconfig.json`)
+ - Follow the project's file structure conventions
+
+2. **Key areas to consider**:
+ - `src/cards/` - Card implementations
+ - `src/delegates/` - Business logic and data retrieval
+ - `src/html/` - HTML rendering components
+ - `src/hass/` - Home Assistant integration code
+ - `src/common/` - Shared utilities
+ - `src/types/` - TypeScript type definitions
+
+### Step 4: Write Tests
+
+1. **Test coverage**:
+ - **PREFER updating existing tests** over creating many new test cases
+ - When possible, add assertions to existing tests that already cover similar functionality
+ - Create or update test files in `test/` directory matching the source structure
+ - Follow existing test patterns (check `test/` directory for examples)
+ - Use Mocha test framework (check `.mocharc.json` and `mocha.setup.ts`)
+
+2. **Test requirements**:
+ - **Keep tests concise**: Aim for 1-2 focused test cases, or update existing tests to cover multiple scenarios
+ - Unit tests for new functions and methods
+ - Edge case testing (when necessary, but consolidate into existing tests when possible)
+ - Integration tests if applicable
+ - Ensure tests pass: `yarn test` or `npm test`
+
+3. **Test file naming**:
+ - Test files should match source files with `.spec.ts` extension
+ - Example: `src/cards/device-card/card.ts` → `test/cards/device-card/card.spec.ts`
+
+4. **Test consolidation strategy**:
+ - **Reuse existing setup/mocks**: Before creating new test cases, check if existing tests already have similar mocks, stubs, or setup code that can be reused
+ - Review existing tests to see if new functionality can be tested alongside existing assertions
+ - Update existing test data/mocks to include new scenarios rather than creating separate tests
+ - Only create new test cases when the functionality is truly distinct and cannot be tested within existing tests
+ - **Avoid duplicating setup code**: If multiple tests need similar mocks or stubs, consider:
+ - Adding shared setup to `beforeEach` hooks
+ - Extending existing mock data structures
+ - Creating helper functions for common test setup
+
+5. **Test quality review**:
+ - **Review the entire test file** after making changes to ensure:
+ - No duplicative tests that test the same thing in slightly different ways
+ - No low-value tests that don't add meaningful coverage
+ - Tests are well-organized and follow the existing patterns
+ - Setup code is not unnecessarily duplicated across tests
+ - If you notice duplicative or low-value tests while working, consider removing or consolidating them
+ - Focus on tests that provide real value: catching bugs, ensuring correctness, and documenting expected behavior
+
+### Step 5: Update Documentation
+
+1. **README.md updates**:
+ - If adding a new feature, add it to the "Features" section
+ - Update "Configuration Options" table if adding new config options
+ - Add example configurations in "Example Configurations" section
+ - Update the "Project Roadmap" section (see Step 7)
+
+2. **Code comments**:
+ - Add JSDoc comments for public functions and classes
+ - Document complex logic and algorithms
+ - Explain non-obvious decisions
+
+3. **Translation files** (if adding user-facing strings):
+ - Update `src/translations/en.json` (English)
+ - Consider updating other language files: `fr.json`, `pt.json`, `ru.json`
+ - Follow the existing translation structure
+
+### Step 6: Create/Update Release Notes
+
+1. **Release notes format**:
+ - Create or update a release notes file (check if one exists, otherwise create `RELEASE_NOTES.md` or similar)
+ - Format entries clearly with issue/PR references
+
+2. **Release notes structure**:
+ - **Main header**: Release title with 2 random emojis at the end
+ - **Each bug/feature**: Use `##` heading (level 2) for each bug fix or feature, starting with a relevant emoji
+ - **Notes under each section**: Small descriptive notes under each heading
+
+3. **Release notes content**:
+ - **Bug fixes**: "Fixed [description] - fixes #[issue-number]"
+ - **New features**: "Added [feature name] - thanks @[username] - fixes #[issue-number]"
+ - **Enhancements**: "Improved [description] - fixes #[issue-number]"
+ - **Breaking changes**: Clearly mark with "⚠️ BREAKING CHANGE:" prefix
+
+4. **Example format**:
+
+ ```markdown
+ # Hidden Entity Filtering & Dark Mode!🎉✨
+
+ ## 🔍 Hidden Entity Filtering
+
+ Hidden entities are now automatically filtered out from device cards, matching Home Assistant's more-info popup behavior - thanks @warmfire540 - fixes #43
+
+ ## 🌙 Dark Mode Support
+
+ Added dark mode theme option for better visibility in low-light environments - thanks @username - fixes #123
+ ```
+
+5. **Home Assistant user-friendly language**:
+ - Write in clear, non-technical language
+ - Focus on what users can do or what problems are solved
+ - Avoid internal implementation details
+ - Use Home Assistant terminology where appropriate
+
+### Step 7: Update README Roadmap (for New Features)
+
+1. **Check if it's a new feature**:
+ - If the issue is a feature request or adds new functionality
+ - If it's a bug fix, skip this step
+
+2. **Add to roadmap**:
+ - Locate the "Project Roadmap" section in README.md
+ - Add a new entry in the format:
+ ```markdown
+ - [ ] **`Feature Name`**: Description of feature - thanks @[username]
+ ```
+ - Use present tense for completed features (change `[ ]` to `[x]` after implementation)
+ - Use future tense for planned features
+
+3. **Thank the contributor**:
+ - If the issue was opened by a GitHub user, include their username
+ - Format: `- thanks @[username]`
+ - If multiple contributors, list them all
+
+### Step 8: Final Checklist
+
+Before completing, verify:
+
+- [ ] All code changes are implemented
+- [ ] All tests are written and passing
+- [ ] **Test quality**: Reviewed test files for duplicative or low-value tests that could be removed
+- [ ] **Test reuse**: Confirmed that existing test setup/mocks were reused where possible
+- [ ] Documentation is updated (README.md, code comments)
+- [ ] Release notes are created/updated
+- [ ] README roadmap is updated (if new feature)
+- [ ] Code follows project style guidelines
+- [ ] TypeScript types are correct
+- [ ] No linter errors
+- [ ] Translation files updated (if needed)
+
+### Step 9: Summary
+
+Provide a summary of:
+
+- What was implemented
+- Files created/modified
+- Test coverage added
+- Documentation updates
+- Release notes entry
+- Roadmap update (if applicable)
+
+## Notes
+
+- **CRITICAL**: This skill operates in PLAN MODE - always present the plan first and wait for user approval
+- Never implement code changes without showing the plan and getting user confirmation
+- Always maintain consistency with existing code patterns
+- Follow the project's TypeScript and testing conventions
+- Ensure backward compatibility unless it's a breaking change
+- Consider Home Assistant version compatibility
+- Test with multiple browsers if UI changes are involved
+- Keep release notes user-friendly and focused on user benefits
+
+## Plan Presentation Format
+
+When presenting the plan, use this structure:
+
+````markdown
+## Plan for Issue #[number]: [Title]
+
+### Issue Summary
+
+[Brief summary of what needs to be done]
+
+### Files to Create/Modify
+
+- `path/to/file1.ts` - [what will change]
+- `path/to/file2.ts` - [what will change]
+- ...
+
+### Implementation Approach
+
+[High-level description of how you'll implement the solution]
+
+### Test Strategy
+
+- Test file: `test/path/to/file1.spec.ts`
+ - **Prefer updating existing tests** rather than creating many new test cases
+ - **Reuse existing setup/mocks**: [describe what existing mocks or setup will be reused]
+ - If updating existing test: [which test and what will be added]
+ - If new test needed: [brief description of why and what it covers, and how it reuses existing setup]
+ - Aim for 1-2 focused test cases total
+ - **Review test file**: Check for any duplicative or low-value tests that could be removed or consolidated
+
+### Documentation Updates
+
+- README.md: [what sections will be updated]
+- Code comments: [what will be documented]
+- Translations: [if applicable]
+
+### Release Notes Draft
+
+```markdown
+## [Emoji] [Feature/Bug Name]
+
+Brief description, yaml example, doc links, etc.
+```
+````
+
+### Roadmap Entry Draft (if new feature)
+
+[Draft of the roadmap entry]
+
+---
+
+**Ready to proceed?** Please review the plan above and let me know if you'd like me to continue with implementation.
+
+```
+
+## Example Workflow
+
+1. User provides: "Solve issue #123: Add dark mode support"
+2. Fetch issue details from GitHub
+3. **PLAN MODE**: Create comprehensive plan:
+ - Files to modify: `src/cards/device-card/styles.ts`, `src/cards/device-card/types.ts`, `src/cards/device-card/editor.ts`
+ - Tests: Update existing test in `test/cards/device-card/card.spec.ts` to include dark mode scenarios (prefer updating over creating new tests)
+ - Documentation: Update README.md Features section, add config option to table
+ - Release notes draft: "## Dark Mode Support\n\nAdded dark mode theme option"
+ - Roadmap draft: "- [ ] **`Dark mode support`**: Add dark mode theme option - thanks @username"
+4. **PRESENT PLAN TO USER** - Wait for approval
+5. **ONLY AFTER APPROVAL**: Implement code changes
+6. **ONLY AFTER APPROVAL**: Create/update test files
+7. **ONLY AFTER APPROVAL**: Update documentation
+8. **ONLY AFTER APPROVAL**: Create/update release notes
+9. **ONLY AFTER APPROVAL**: Update roadmap
+10. Summary: List all changes made
+```
diff --git a/README.md b/README.md
index 30666583..3ed5e262 100644
--- a/README.md
+++ b/README.md
@@ -127,4 +127,4 @@ This project is protected under the MIT License. For more details, refer to the
- [x] **`Frosted Glass Theme Support`**: automatic detection and styling for Frosted Glass themes with transparent blurred card effects - thanks @devkaiwang
- [x] **`Sensor Improvements`**: feature requests to make sensors awesome - thanks @MelleD
- [x] **`Brightness Slider`**: entity transforms into slider - thanks @tmaihoff, @hfalk
-- [x] **`Entity Badges`**: dynamic badge overlays- thanks @ojm88
\ No newline at end of file
+- [x] **`Entity Badges`**: dynamic badge overlays- thanks @ojm88
diff --git a/docs/configuration/BADGE-CONFIGURATION.md b/docs/configuration/BADGE-CONFIGURATION.md
index 02000207..8e8fa38b 100644
--- a/docs/configuration/BADGE-CONFIGURATION.md
+++ b/docs/configuration/BADGE-CONFIGURATION.md
@@ -159,7 +159,7 @@ When using state-based badges (no `mode` specified), the `states` array uses the
| Name | Type | Default | Description |
| ---------- | ------ | ------------ | -------------------------------------------------------- |
| state | string | **Required** | Entity state or attribute value to match exactly |
-| operator | string | `eq` | Comparison operator: `eq` (equal) or `ne` (not equal) |
+| operator | string | `eq` | Comparison operator: `eq` (equal) or `ne` (not equal) |
| icon_color | string | **Required** | Color to use when this state is active |
| icon | string | none | Icon to use when this state is active |
| attribute | string | none | Optional attribute name to match instead of entity state |
@@ -292,7 +292,7 @@ entities:
- state: 'ok'
operator: ne
icon: mdi:alert-circle
- icon_color: red # Badge appears for all states except 'ok'
+ icon_color: red # Badge appears for all states except 'ok'
```
## Badge Styling
diff --git a/docs/configuration/ENTITY-COLOR-CONFIGURATION.md b/docs/configuration/ENTITY-COLOR-CONFIGURATION.md
index ca68dede..579d8d1b 100644
--- a/docs/configuration/ENTITY-COLOR-CONFIGURATION.md
+++ b/docs/configuration/ENTITY-COLOR-CONFIGURATION.md
@@ -107,7 +107,7 @@ entities:
icon_color: green
- state: 'ok'
operator: ne
- icon_color: red # All other states show red
+ icon_color: red # All other states show red
```
This is particularly useful for entities with enum states where you want to match "all states except X" without listing every possible state explicitly.
diff --git a/docs/configuration/ENTITY-CONFIGURATION.md b/docs/configuration/ENTITY-CONFIGURATION.md
index 17498155..79316c15 100644
--- a/docs/configuration/ENTITY-CONFIGURATION.md
+++ b/docs/configuration/ENTITY-CONFIGURATION.md
@@ -309,7 +309,7 @@ entities:
icon_color: green
- state: 'ok'
operator: ne
- icon_color: red # All other states show red
+ icon_color: red # All other states show red
```
## State Matching Operators
@@ -330,7 +330,7 @@ entities:
icon_color: green
- state: 'ok'
operator: ne
- icon_color: red # All states except 'ok' show red
+ icon_color: red # All states except 'ok' show red
```
**Note**: State configurations are evaluated in order, so more specific matches (like `eq`) should be placed before broader matches (like `ne`).
diff --git a/mocha.setup.ts b/mocha.setup.ts
index 3cf42663..ca057bfe 100644
--- a/mocha.setup.ts
+++ b/mocha.setup.ts
@@ -17,8 +17,12 @@ global.window = dom.window as any;
global.document = dom.window.document;
global.requestAnimationFrame = (callback) => setTimeout(callback, 0);
// Ensure globalThis also points to window for addEventListener support
-(globalThis as any).addEventListener = dom.window.addEventListener.bind(dom.window);
-(globalThis as any).removeEventListener = dom.window.removeEventListener.bind(dom.window);
+(globalThis as any).addEventListener = dom.window.addEventListener.bind(
+ dom.window,
+);
+(globalThis as any).removeEventListener = dom.window.removeEventListener.bind(
+ dom.window,
+);
(globalThis as any).dispatchEvent = dom.window.dispatchEvent.bind(dom.window);
// Add missing DOM features
diff --git a/package.json b/package.json
index b2f87785..9ba5f37d 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@open-wc/testing": "^4.0.0",
- "@parcel/transformer-inline-string": "^2.16.3",
+ "@parcel/transformer-inline-string": "^2.16.4",
"@testing-library/dom": "^10.4.1",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/chai": "^5.2.3",
@@ -31,11 +31,11 @@
"@types/mocha": "^10.0.10",
"@types/sinon": "^21.0.0",
"chai": "^6.2.2",
- "jsdom": "^27.4.0",
+ "jsdom": "^28.1.0",
"mocha": "^11.7.5",
"nyc": "^17.1.0",
- "parcel": "^2.16.3",
- "prettier": "3.8.0",
+ "parcel": "^2.16.4",
+ "prettier": "3.8.1",
"prettier-plugin-organize-imports": "^4.3.0",
"proxyquire": "^2.1.3",
"sinon": "^21.0.1",
diff --git a/src/cards/components/badge/badge.ts b/src/cards/components/badge/badge.ts
index bcebfd17..6d9af45d 100644
--- a/src/cards/components/badge/badge.ts
+++ b/src/cards/components/badge/badge.ts
@@ -1,15 +1,16 @@
import { HassUpdateMixin } from '@cards/mixins/hass-update-mixin';
-import { getState } from '@delegates/retrievers/state';
+import { SubscribeEntityStateMixin } from '@cards/mixins/subscribe-entity-state-mixin';
import { getMatchingBadgeState } from '@delegates/utils/badge-state';
import { renderTileBadge } from '@hass/panels/lovelace/cards/tile/badges/tile-badge';
-import type { HomeAssistant } from '@hass/types';
import { stylesToHostCss } from '@theme/util/style-converter';
+import type { Config } from '@type/config';
import type { BadgeConfig } from '@type/config/entity';
-import type { EntityInformation } from '@type/room';
+import { d } from '@util/debug';
import { CSSResult, LitElement, html, nothing, type TemplateResult } from 'lit';
-import { property, state } from 'lit/decorators.js';
+import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { styles } from './styles';
+const equal = require('fast-deep-equal');
/**
* Badge Component
@@ -17,23 +18,18 @@ import { styles } from './styles';
* A small Lit element that renders a badge overlay for an entity.
* Badges can display entity state icons or custom icons based on configuration.
*/
-export class Badge extends HassUpdateMixin(LitElement) {
- /**
- * Home Assistant instance
- */
- private _hass!: HomeAssistant;
-
+export class Badge extends SubscribeEntityStateMixin(
+ HassUpdateMixin(LitElement),
+) {
/**
* Badge configuration
*/
- @property({ type: Object })
- config!: BadgeConfig;
+ private _config!: BadgeConfig;
/**
- * Parent entity information
+ * Card config for debug
*/
- @property({ type: Object })
- entity!: EntityInformation;
+ cardConfig?: Config;
/**
* Badge position (reflective attribute)
@@ -41,9 +37,6 @@ export class Badge extends HassUpdateMixin(LitElement) {
@property({ type: String, reflect: true, attribute: 'position' })
position: string = 'top-right';
- @state()
- private _entity?: EntityInformation;
-
/**
* Returns the component's styles
*/
@@ -52,43 +45,43 @@ export class Badge extends HassUpdateMixin(LitElement) {
}
/**
- * Updates the component's state when Home Assistant state changes
- * @param {HomeAssistant} hass - The Home Assistant instance
+ * Badge configuration
*/
- // @ts-ignore
- override set hass(hass: HomeAssistant) {
- this._hass = hass;
-
- // Determine which entity to use for the badge (defaults to parent entity)
- const badgeEntityState = this.config.entity_id
- ? getState(this._hass.states, this.config.entity_id)
- : this.entity.state;
-
- // Create badge entity information
- this._entity = {
- config: this.entity.config,
- state: badgeEntityState,
- };
+ set config(config: BadgeConfig) {
+ d(this.cardConfig, 'badge', 'set config');
+ if (equal(config, this._config)) return;
// Set position (convert underscores to hyphens for CSS)
- const position = this.config.position ?? 'top_right';
+ const position = config.position ?? 'top_right';
this.position = position.replaceAll('_', '-');
+
+ this.entityId = config.entity_id;
+ this._config = config;
}
+ /**
+ * Render the badge
+ */
public override render(): TemplateResult | typeof nothing {
- if (!this._hass || !this._entity?.state) {
+ d(this.cardConfig, 'badge', 'render');
+
+ // entity_id is always set (by renderBadgeElements from user config or parent)
+ const state = this._subscribedEntityState;
+ const hass = this.hass;
+ if (!hass || !state) {
return nothing;
}
// For homeassistant mode, use renderTileBadge (HA's native badge helper)
- if (this.config.mode === 'homeassistant') {
- return renderTileBadge(this._entity.state, this._hass);
+ const config = this._config;
+ if (config.mode === 'homeassistant') {
+ return renderTileBadge(state, hass);
}
- const matchingState = getMatchingBadgeState(this._entity, this.config);
+ const matchingState = getMatchingBadgeState(state, config);
// For if_match mode, only render if a state match is found
- if (this.config.mode === 'if_match' && !matchingState) {
+ if (config.mode === 'if_match' && !matchingState) {
return nothing;
}
@@ -100,9 +93,9 @@ export class Badge extends HassUpdateMixin(LitElement) {
})}
>
`;
diff --git a/src/cards/components/problem/dialog/problem-dialog.ts b/src/cards/components/problem/dialog/problem-dialog.ts
index fd4277e3..1d173e89 100644
--- a/src/cards/components/problem/dialog/problem-dialog.ts
+++ b/src/cards/components/problem/dialog/problem-dialog.ts
@@ -3,7 +3,9 @@ import '@cards/components/problem/list/problem-entity-list';
import { HassUpdateMixin } from '@cards/mixins/hass-update-mixin';
import { fireEvent } from '@hass/common/dom/fire_event';
import type { HassDialog } from '@hass/dialogs/make-dialog-manager';
+import type { Config } from '@type/config';
import type { EntityState } from '@type/room';
+import { d } from '@util/debug';
import { LitElement, html, nothing, type TemplateResult } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { createCloseHeading } from './create-close-heading';
@@ -19,6 +21,11 @@ export class ProblemDialog
extends HassUpdateMixin(LitElement)
implements HassDialog
{
+ /**
+ * Card config for debug (optional)
+ */
+ private _config?: Config;
+
/**
* Array of problem entity states
*/
@@ -36,6 +43,7 @@ export class ProblemDialog
*/
showDialog(params: ProblemDialogParams): void {
this.problemEntities = params.entities;
+ this._config = params.config;
this._opened = true;
}
@@ -57,6 +65,7 @@ export class ProblemDialog
* Renders the component
*/
override render(): TemplateResult | typeof nothing {
+ d(this._config, 'problem-dialog', 'render');
if (!this.hass || this.problemEntities.length === 0) {
return nothing;
}
@@ -72,6 +81,7 @@ export class ProblemDialog
`;
diff --git a/src/cards/components/problem/dialog/show-dialog-problem.ts b/src/cards/components/problem/dialog/show-dialog-problem.ts
index 9187ddd4..059032c8 100644
--- a/src/cards/components/problem/dialog/show-dialog-problem.ts
+++ b/src/cards/components/problem/dialog/show-dialog-problem.ts
@@ -1,8 +1,10 @@
import { fireEvent } from '@hass/common/dom/fire_event';
+import type { Config } from '@type/config';
import type { EntityState } from '@type/room';
export interface ProblemDialogParams {
entities: EntityState[];
+ config?: Config;
}
export const loadProblemDialog = () =>
diff --git a/src/cards/components/problem/list/problem-entity-list.ts b/src/cards/components/problem/list/problem-entity-list.ts
index 0f2d0879..d0cc3a00 100644
--- a/src/cards/components/problem/list/problem-entity-list.ts
+++ b/src/cards/components/problem/list/problem-entity-list.ts
@@ -2,7 +2,9 @@
import '@cards/components/problem/row/problem-entity-row';
import { HassUpdateMixin } from '@cards/mixins/hass-update-mixin';
import { localize } from '@localize/localize';
+import type { Config } from '@type/config';
import type { EntityState } from '@type/room';
+import { d } from '@util/debug';
import { CSSResult, LitElement, html, nothing, type TemplateResult } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
@@ -16,6 +18,11 @@ import { styles } from './styles';
*/
@customElement('problem-entity-list')
export class ProblemEntityList extends HassUpdateMixin(LitElement) {
+ /**
+ * Card config for debug (optional)
+ */
+ config?: Config;
+
/**
* Array of problem entity states
*/
@@ -26,6 +33,7 @@ export class ProblemEntityList extends HassUpdateMixin(LitElement) {
* Renders the component
*/
override render(): TemplateResult | typeof nothing {
+ d(this.config, 'problem-entity-list', 'render');
if (!this.hass) {
return nothing;
}
@@ -47,6 +55,7 @@ export class ProblemEntityList extends HassUpdateMixin(LitElement) {
`,
)}
diff --git a/src/cards/components/problem/row/problem-entity-row.ts b/src/cards/components/problem/row/problem-entity-row.ts
index 8b59e287..0b797a31 100644
--- a/src/cards/components/problem/row/problem-entity-row.ts
+++ b/src/cards/components/problem/row/problem-entity-row.ts
@@ -6,7 +6,9 @@ import { stateActive } from '@hass/common/entity/state_active';
import '@hass/state/more-info-mixin';
import { stateDisplay } from '@html/state-display';
import { localize } from '@localize/localize';
+import type { Config } from '@type/config';
import type { EntityState } from '@type/room';
+import { d } from '@util/debug';
import { CSSResult, LitElement, html, nothing, type TemplateResult } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { styles } from './styles';
@@ -19,6 +21,11 @@ import { styles } from './styles';
*/
@customElement('problem-entity-row')
export class ProblemEntityRow extends HassUpdateMixin(LitElement) {
+ /**
+ * Card config for debug (optional)
+ */
+ config?: Config;
+
/**
* The problem entity state
*/
@@ -38,6 +45,7 @@ export class ProblemEntityRow extends HassUpdateMixin(LitElement) {
* Renders the component
*/
override render(): TemplateResult | typeof nothing {
+ d(this.config, 'problem-entity-row', 'render');
if (!this.entity || !this.hass) {
return nothing;
}
diff --git a/src/cards/components/room-state-icon/room-state-icon.ts b/src/cards/components/room-state-icon/room-state-icon.ts
index be38fe29..b60f8e62 100644
--- a/src/cards/components/room-state-icon/room-state-icon.ts
+++ b/src/cards/components/room-state-icon/room-state-icon.ts
@@ -145,12 +145,12 @@ export class RoomStateIcon extends HassUpdateMixin(LitElement) {
*/
// @ts-ignore
override set hass(hass: HomeAssistant) {
+ d(this._config, 'room-state-icon', 'set hass');
this._image = hasEntityFeature(this.entity, 'use_entity_icon')
? undefined
: this.entity?.state?.attributes?.entity_picture;
if (this._image) {
- d(this._config, 'room-state-icon - image', this._image);
this.image = true;
this.iconBackground = true;
this._hideIconContent = true;
@@ -160,13 +160,18 @@ export class RoomStateIcon extends HassUpdateMixin(LitElement) {
this._hideIconContent = this.isMainRoomEntity
? this._config?.background?.options?.includes('hide_icon_only') || false
: false;
- this.image = false;
+
+ // regression fix for #383 - in future handle the image logic internally
+ // but this resets the image to false when the entity_picture is removed for #333 still
+ this.image =
+ this._config?.background?.options?.includes('icon_background') ?? false;
}
this._hass = hass;
}
public override render(): TemplateResult | typeof nothing {
+ d(this._config, 'room-state-icon', 'render');
const { state } = this.entity;
if (!state) return nothing;
@@ -189,8 +194,6 @@ export class RoomStateIcon extends HassUpdateMixin(LitElement) {
this._config,
);
- d(this._config, 'room-state-icon - iconStyle', iconStyle);
-
const iconStyles = {
...this._config?.styles?.entity_icon,
...(this.isMainRoomEntity
@@ -229,9 +232,9 @@ export class RoomStateIcon extends HassUpdateMixin(LitElement) {
// Render badges (max 4)
const badgeElements = renderBadgeElements(
- this.entity.config.badges,
this.entity,
this._hass,
+ this._config,
);
return html`
diff --git a/src/cards/editor.ts b/src/cards/editor.ts
index 282d7d3d..ef4aa782 100644
--- a/src/cards/editor.ts
+++ b/src/cards/editor.ts
@@ -13,6 +13,7 @@ import type { HASSDomEvent } from '@hass/common/dom/fire_event';
import type { HomeAssistant } from '@hass/types';
import { Task } from '@lit/task';
import type { Config } from '@type/config';
+import { d } from '@util/debug';
import { CSSResult, html, LitElement, nothing, type TemplateResult } from 'lit';
import { state } from 'lit/decorators.js';
import type { Ref } from 'lit/directives/ref.js';
@@ -87,6 +88,7 @@ export class RoomSummaryCardEditor extends LitElement {
* @returns The rendered HTML template
*/
override render() {
+ d(this._config, 'room-summary-card-editor', 'render');
if (!this.hass || !this._config) {
return nothing;
}
@@ -97,6 +99,7 @@ export class RoomSummaryCardEditor extends LitElement {
diff --git a/src/cards/mixins/hass-update-mixin.ts b/src/cards/mixins/hass-update-mixin.ts
index efd4d3e8..2081e477 100644
--- a/src/cards/mixins/hass-update-mixin.ts
+++ b/src/cards/mixins/hass-update-mixin.ts
@@ -1,6 +1,5 @@
import type { HomeAssistant } from '@hass/types';
import type { LitElement } from 'lit';
-import { property } from 'lit/decorators.js';
export interface HassUpdateEvent {
hass: HomeAssistant;
@@ -16,8 +15,15 @@ export const HassUpdateMixin = >(
superClass: T,
) => {
class HassUpdateClass extends superClass implements HassUpdateElement {
- @property({ attribute: false })
- public hass?: HomeAssistant;
+ private __hassValue?: HomeAssistant;
+
+ get hass(): HomeAssistant | undefined {
+ return this.__hassValue;
+ }
+
+ set hass(value: HomeAssistant | undefined) {
+ this.__hassValue = value;
+ }
private readonly _boundHassUpdateHandler =
this._handleHassUpdate.bind(this);
@@ -29,7 +35,10 @@ export const HassUpdateMixin = >(
override disconnectedCallback(): void {
super.disconnectedCallback();
- globalThis.removeEventListener('hass-update', this._boundHassUpdateHandler);
+ globalThis.removeEventListener(
+ 'hass-update',
+ this._boundHassUpdateHandler,
+ );
}
private _handleHassUpdate(event: Event): void {
diff --git a/src/cards/mixins/subscribe-entity-state-mixin.ts b/src/cards/mixins/subscribe-entity-state-mixin.ts
new file mode 100644
index 00000000..429223fb
--- /dev/null
+++ b/src/cards/mixins/subscribe-entity-state-mixin.ts
@@ -0,0 +1,118 @@
+import { subscribeEntityState } from '@delegates/entities/subscribe-trigger';
+import { getState } from '@delegates/retrievers/state';
+import type { HomeAssistant } from '@hass/types';
+import type { SubscriptionUnsubscribe } from '@hass/ws/types';
+import type { EntityState } from '@type/room';
+import type { LitElement } from 'lit';
+import { state } from 'lit/decorators.js';
+const equal = require('fast-deep-equal');
+
+export type Constructor = new (...args: any[]) => T;
+
+export interface SubscribeEntityStateElement {
+ hass?: HomeAssistant;
+}
+
+/**
+ * Mixin that subscribes to entity state changes via subscribe_trigger.
+ * Set entityIdToSubscribe to specify which entity to watch.
+ * Read _subscribedEntityState for the current state (undefined when not subscribed).
+ */
+export const SubscribeEntityStateMixin = <
+ T extends Constructor,
+>(
+ superClass: T,
+) => {
+ class SubscribeEntityStateClass extends superClass {
+ /**
+ * The unsubscribe function for the subscription.
+ */
+ private _unsubscribe?: SubscriptionUnsubscribe;
+
+ /**
+ * The entity_id of the subscribed entity.
+ */
+ private _subscribedEntityId?: string;
+
+ /**
+ * The entity_id to subscribe to. Set this property to specify which entity to watch.
+ */
+ protected entityId?: string;
+
+ /**
+ * The current state of the subscribed entity.
+ * Updates cause re-render of the component.
+ */
+ @state()
+ protected _subscribedEntityState?: EntityState;
+
+ /**
+ * Setup the entity subscription.
+ */
+ override connectedCallback(): void {
+ super.connectedCallback();
+ this._setupEntitySubscription();
+ }
+
+ /**
+ * Teardown the entity subscription.
+ */
+ override disconnectedCallback(): void {
+ this._teardownEntitySubscription();
+ super.disconnectedCallback();
+ }
+
+ /**
+ * Teardown the entity subscription.
+ */
+ private _teardownEntitySubscription(): void {
+ if (this._unsubscribe) {
+ this._unsubscribe();
+ this._unsubscribe = undefined;
+ this._subscribedEntityId = undefined;
+ }
+ }
+
+ /**
+ * Setup the entity subscription.
+ */
+ private _setupEntitySubscription(): void {
+ const id = this.entityId;
+ const hass = this.hass;
+
+ if (!id || !hass) {
+ this._teardownEntitySubscription();
+ this._subscribedEntityState = undefined;
+ return;
+ }
+
+ if (this._subscribedEntityId === id) {
+ return;
+ }
+
+ this._teardownEntitySubscription();
+ this._subscribedEntityId = id;
+
+ const initialState = getState(hass.states, id);
+ this._subscribedEntityState = initialState;
+
+ subscribeEntityState(
+ hass,
+ id,
+ ({ variables: { trigger: { from_state, to_state } = {} } = {} }) => {
+ // use getState since it cuts out extra properties like timestamps
+ const fromState = getState({ [id]: from_state }, id);
+ const toState = getState({ [id]: to_state }, id);
+ if (equal(fromState, toState)) return;
+
+ // Update the state if it has changed.
+ this._subscribedEntityState = toState;
+ },
+ ).then((unsubscribe) => {
+ this._unsubscribe = unsubscribe;
+ });
+ }
+ }
+
+ return SubscribeEntityStateClass;
+};
diff --git a/src/delegates/checks/occupancy.ts b/src/delegates/checks/occupancy.ts
index 575eae17..98a027b6 100644
--- a/src/delegates/checks/occupancy.ts
+++ b/src/delegates/checks/occupancy.ts
@@ -1,5 +1,6 @@
import { stateActive } from '@hass/common/entity/state_active';
import type { HomeAssistant } from '@hass/types';
+import { processHomeAssistantColors } from '@theme/colors';
import type { AlarmConfig } from '@type/config';
/**
@@ -52,7 +53,8 @@ const getAlarmCssVars = (
// Set card border variable (3px solid) unless disabled
const isCardBorderDisabled = config.options?.includes('disabled_card_styles');
if (!isCardBorderDisabled) {
- const borderColor = config.card_border_color ?? defaultColor;
+ const borderColor =
+ processHomeAssistantColors(config.card_border_color) ?? defaultColor;
vars[`--${prefix}-card-border`] = `3px solid ${borderColor}`;
vars[`--${prefix}-card-border-color`] = borderColor;
@@ -69,7 +71,8 @@ const getAlarmCssVars = (
// Icon color styling
const isIconColorDisabled = config.options?.includes('disable_icon_styles');
if (!isIconColorDisabled) {
- const iconColor = config.icon_color ?? defaultColor;
+ const iconColor =
+ processHomeAssistantColors(config.icon_color) ?? defaultColor;
vars[`--${prefix}-icon-color`] = iconColor;
// Set animation unless disabled
diff --git a/src/delegates/entities/subscribe-trigger.ts b/src/delegates/entities/subscribe-trigger.ts
new file mode 100644
index 00000000..ae0b7872
--- /dev/null
+++ b/src/delegates/entities/subscribe-trigger.ts
@@ -0,0 +1,28 @@
+/**
+ * Subscribe to entity state changes via Home Assistant's subscribe_trigger API.
+ * Only receives events when the specified entity changes (server-side filtering).
+ *
+ * @see https://developers.home-assistant.io/docs/api/websocket#subscribe_trigger
+ */
+
+import type { HomeAssistant } from '@hass/types';
+import type { SubscriptionUnsubscribe } from '@hass/ws/types';
+
+export interface StateTriggerResult {
+ variables: { trigger: Record };
+ context: { id: string; parent_id: string | null; user_id: string | null };
+}
+
+/**
+ * Subscribe to state changes for a single entity.
+ * Returns a Promise that resolves to the unsubscribe function.
+ */
+export const subscribeEntityState = (
+ hass: HomeAssistant,
+ entityId: string,
+ onChange: (result: StateTriggerResult) => void,
+): Promise =>
+ hass.connection.subscribeMessage(onChange, {
+ type: 'subscribe_trigger',
+ trigger: { platform: 'state', entity_id: entityId },
+ });
diff --git a/src/delegates/utils/badge-state.ts b/src/delegates/utils/badge-state.ts
index 9ba953ce..42e0d1af 100644
--- a/src/delegates/utils/badge-state.ts
+++ b/src/delegates/utils/badge-state.ts
@@ -1,20 +1,18 @@
-import { meetsStateCondition } from '@util/comparison-utils';
import type { BadgeConfig, StateConfig } from '@type/config/entity';
-import type { EntityInformation } from '@type/room';
+import type { EntityState } from '@type/room';
+import { meetsStateCondition } from '@util/comparison-utils';
/**
* Gets the matching badge state configuration for a badge
*
- * @param entity - The entity information containing state
+ * @param state - The entity state
* @param badge - The badge configuration
* @returns The matching StateConfig if found, undefined otherwise
*/
export const getMatchingBadgeState = (
- entity: EntityInformation,
+ state: EntityState,
badge: BadgeConfig,
): StateConfig | undefined => {
- const { state } = entity;
-
if (!badge.states || !state) {
return undefined;
}
diff --git a/src/delegates/utils/hide-yo-sensors.ts b/src/delegates/utils/hide-yo-sensors.ts
index ecf13355..ef275a96 100644
--- a/src/delegates/utils/hide-yo-sensors.ts
+++ b/src/delegates/utils/hide-yo-sensors.ts
@@ -9,6 +9,7 @@ import type { SensorConfig } from '@type/config/sensor';
import type { EntityState } from '@type/room';
import type { SensorData } from '@type/sensor';
import { calculateAverages } from './sensor-averages';
+import { probablyClassSensorUsersMadeThisComplex } from './sensor-sifter';
/**
* Helper function to extract entity_id from LightConfig
@@ -41,14 +42,11 @@ const isAmbientLight = (light: LightConfig): boolean => {
* @returns SensorData object containing individual and averaged sensor information, plus light entities.
*/
export const getSensors = (hass: HomeAssistant, config: Config): SensorData => {
- const skipDefaultEntities = hasFeature(config, 'exclude_default_entities');
const multiLightEnabled = hasFeature(config, 'multi_light_background');
const hideHiddenEntities = hasFeature(config, 'hide_hidden_entities');
// Get area information to check for configured temperature/humidity sensors
const area = getArea(hass.areas, config.area);
- const areaHasTemperatureSensor = !!area?.temperature_entity_id;
- const areaHasHumiditySensor = !!area?.humidity_entity_id;
// Default sensor classes if not specified
const sensorClasses = config.sensor_classes || [
@@ -138,18 +136,6 @@ export const getSensors = (hass: HomeAssistant, config: Config): SensorData => {
}
};
- // Helper function to check if entity is a class sensor
- const isClassSensor = (
- state: EntityState,
- deviceClass: string | undefined,
- ): boolean => {
- return (
- state.domain === 'sensor' &&
- !!deviceClass &&
- sensorClasses.includes(deviceClass)
- );
- };
-
// Process all entities in the area
Object.values(hass.entities).forEach((entity) => {
// Skip hidden entities if the feature is enabled
@@ -214,39 +200,15 @@ export const getSensors = (hass: HomeAssistant, config: Config): SensorData => {
return;
}
- // If we're skipping default entities, don't process further
- if (skipDefaultEntities) return;
-
- // Check if this is the area's default temperature/humidity sensor
- const isAreaDefaultTemp =
- areaHasTemperatureSensor &&
- entity.entity_id === area.temperature_entity_id;
- const isAreaDefaultHumidity =
- areaHasHumiditySensor && entity.entity_id === area.humidity_entity_id;
-
- // If this is an area default sensor, add it to classSensors (unless already configured)
+ // Check if this entity qualifies as a class-based sensor for averaging
if (
- (isAreaDefaultTemp || isAreaDefaultHumidity) &&
- !isConfigSensor &&
- !isThresholdEntity
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ config,
+ area,
+ sensorClasses,
+ )
) {
- const deviceClass = state.attributes?.device_class;
- if (isClassSensor(state, deviceClass)) {
- classSensors.push(state);
- }
- return;
- }
-
- // Check if this is a sensor with a device class we care about
- const deviceClass = state.attributes?.device_class;
- if (isClassSensor(state, deviceClass)) {
- // Skip temperature/humidity sensors if the area has configured defaults
- if (
- (deviceClass === 'temperature' && areaHasTemperatureSensor) ||
- (deviceClass === 'humidity' && areaHasHumiditySensor)
- ) {
- return;
- }
classSensors.push(state);
}
});
diff --git a/src/delegates/utils/sensor-sifter.ts b/src/delegates/utils/sensor-sifter.ts
new file mode 100644
index 00000000..95f86bbb
--- /dev/null
+++ b/src/delegates/utils/sensor-sifter.ts
@@ -0,0 +1,51 @@
+import { hasFeature } from '@config/feature';
+import type { AreaRegistryEntry } from '@hass/data/area/area_registry';
+import type { Config } from '@type/config';
+import type { EntityState } from '@type/room';
+
+/**
+ * Determines whether an entity should be collected as a class-based sensor
+ * for averaging. Handles area-default sensor logic: when an area has a
+ * configured default temperature/humidity sensor, only that specific sensor
+ * is included and other sensors of the same class are skipped.
+ */
+export const probablyClassSensorUsersMadeThisComplex = (
+ state: EntityState,
+ config: Config,
+ area: AreaRegistryEntry | undefined,
+ sensorClasses: string[],
+): boolean => {
+ if (hasFeature(config, 'exclude_default_entities')) return false;
+
+ const deviceClass = state.attributes?.device_class;
+ if (
+ state.domain !== 'sensor' ||
+ !deviceClass ||
+ !sensorClasses.includes(deviceClass)
+ ) {
+ return false;
+ }
+
+ const areaHasTemp = !!area?.temperature_entity_id;
+ const areaHasHumidity = !!area?.humidity_entity_id;
+
+ const isAreaDefaultTemp =
+ areaHasTemp && state.entity_id === area?.temperature_entity_id;
+ const isAreaDefaultHumidity =
+ areaHasHumidity && state.entity_id === area?.humidity_entity_id;
+
+ // Area default sensors are always included
+ if (isAreaDefaultTemp || isAreaDefaultHumidity) {
+ return true;
+ }
+
+ // Skip non-default temp/humidity sensors when area has configured defaults
+ if (
+ (deviceClass === 'temperature' && areaHasTemp) ||
+ (deviceClass === 'humidity' && areaHasHumidity)
+ ) {
+ return false;
+ }
+
+ return true;
+};
diff --git a/src/hass/types.ts b/src/hass/types.ts
index 50d25136..2c0ebbb1 100644
--- a/src/hass/types.ts
+++ b/src/hass/types.ts
@@ -8,6 +8,7 @@ import type { DeviceRegistryEntry } from './data/device_registry';
import type { EntityRegistryDisplayEntry } from './data/entity_registry';
import type { Themes } from './data/ws-themes';
import type {
+ Connection,
HassEntities,
HassEntity,
HassServiceTarget,
@@ -33,6 +34,7 @@ export interface ServiceCallRequest {
}
export interface HomeAssistant {
+ connection: Connection;
states: HassEntities;
entities: Record;
devices: Record;
diff --git a/src/hass/ws/types.ts b/src/hass/ws/types.ts
index 70e84b2a..bac15aeb 100644
--- a/src/hass/ws/types.ts
+++ b/src/hass/ws/types.ts
@@ -2,6 +2,8 @@
* https://github.com/home-assistant/home-assistant-js-websocket/blob/master/lib/types.ts
*/
+export type SubscriptionUnsubscribe = () => Promise;
+
export type MessageBase = {
id?: number;
type: string;
@@ -40,3 +42,14 @@ export type HassServiceTarget = {
floor_id?: string | string[];
label_id?: string | string[];
};
+
+export interface Connection {
+ subscribeMessage(
+ callback: (result: Result) => void,
+ subscribeMessage: MessageBase,
+ options?: {
+ resubscribe?: boolean;
+ preCheck?: () => boolean | Promise;
+ },
+ ): Promise;
+}
diff --git a/src/html/badge-squad.ts b/src/html/badge-squad.ts
index 9529e008..8e512601 100644
--- a/src/html/badge-squad.ts
+++ b/src/html/badge-squad.ts
@@ -1,26 +1,32 @@
import type { HomeAssistant } from '@hass/types';
-import type { BadgeConfig } from '@type/config/entity';
+import type { Config } from '@type/config';
import type { EntityInformation } from '@type/room';
import { html, type TemplateResult } from 'lit';
/**
* Renders badge elements for an entity.
* Limits badges to a maximum of 4.
+ * Ensures each badge has entity_id (from user config or parent entity).
*
- * @param badges - Array of badge configurations (will be limited to first 4)
- * @param entity - The entity information
+ * @param entity - The entity information (used for entity_id and entityConfig)
* @param hass - Home Assistant instance
+ * @param config - Card config for debug (optional)
* @returns Array of badge template results
*/
export const renderBadgeElements = (
- badges: BadgeConfig[] | undefined,
entity: EntityInformation,
hass: HomeAssistant,
-): TemplateResult[] => {
- const badgeConfigs = badges?.slice(0, 4) ?? [];
- return badgeConfigs.map(
- (badge) => html`
-
- `,
- );
-};
+ config?: Config,
+): TemplateResult[] | undefined =>
+ entity.config.badges?.slice(0, 4)?.map((badge) => {
+ return html`
+
+ `;
+ });
diff --git a/src/html/icon.ts b/src/html/icon.ts
index 80e96e86..af4f51dd 100644
--- a/src/html/icon.ts
+++ b/src/html/icon.ts
@@ -42,7 +42,10 @@ export const renderProblemIndicator = (
class="status-entities"
?has-problems=${problemExists}
@click=${() =>
- showProblemDialog(element, { entities: problemSensors })}
+ showProblemDialog(element, {
+ entities: problemSensors,
+ config,
+ })}
>${problemSensors.length}`
: nothing}
diff --git a/src/types/config/index.ts b/src/types/config/index.ts
index 8b167556..3dfa04bd 100644
--- a/src/types/config/index.ts
+++ b/src/types/config/index.ts
@@ -135,11 +135,19 @@ export interface Config {
/** Options to enable or disable features **/
features?: Features[];
+
+ /** Debug configuration. When present, enables scoped debug logging to console. */
+ debug?: {
+ /** Only log for these components (e.g. ['room-summary-card']). Omit = all components */
+ scope?: string[];
+
+ /** Only log these categories (e.g. ['render']). Omit = all categories */
+ categories?: string[];
+ };
}
/** Features to enable or disable functionality */
export type Features =
- | 'debug'
| 'hide_area_stats'
| 'hide_climate_label'
| 'hide_room_icon'
diff --git a/src/util/debug.ts b/src/util/debug.ts
index acb2b055..75cdf223 100644
--- a/src/util/debug.ts
+++ b/src/util/debug.ts
@@ -1,14 +1,25 @@
-import { hasFeature } from '@config/feature';
import type { Config } from '@type/config';
/**
- * Logs debug messages to the console if the 'debug' feature is enabled in the configuration.
+ * Logs debug messages to the console when config.debug is present.
+ * Supports scoping by component and/or category.
*
- * @param config - The configuration object used to determine if debugging is enabled.
- * @param args - The arguments to be logged to the console.
+ * @param config - The configuration object. When undefined, no logging occurs.
+ * @param component - Component name (e.g. 'room-summary-card')
+ * @param category - Category (e.g. 'render', 'set hass')
+ * @param args - Additional data to log
*/
-export const d = (config: Config, ...args: any[]) => {
- if (hasFeature(config, 'debug')) {
- console.debug(...args);
- }
+export const d = (
+ config: Config | undefined,
+ component: string,
+ category: string,
+ ...args: any[]
+) => {
+ if (!config?.debug) return;
+
+ const { scope, categories } = config.debug;
+ if (scope?.length && !scope.includes(component)) return;
+ if (categories?.length && !categories.includes(category)) return;
+
+ console.debug(`[${component}] ${category}`, ...args);
};
diff --git a/test/cards/components/badge/badge.spec.ts b/test/cards/components/badge/badge.spec.ts
index 24855c1d..3229caec 100644
--- a/test/cards/components/badge/badge.spec.ts
+++ b/test/cards/components/badge/badge.spec.ts
@@ -1,18 +1,13 @@
import { Badge } from '@cards/components/badge/badge';
import { styles } from '@cards/components/badge/styles';
-import * as stateRetrieverModule from '@delegates/retrievers/state';
import * as badgeStateModule from '@delegates/utils/badge-state';
import * as renderTileBadgeModule from '@hass/panels/lovelace/cards/tile/badges/tile-badge';
import type { HomeAssistant } from '@hass/types';
import { fixture } from '@open-wc/testing-helpers';
import { createStateEntity } from '@test/test-helpers';
import * as styleConverterModule from '@theme/util/style-converter';
-import type {
- BadgeConfig,
- EntityConfig,
- StateConfig,
-} from '@type/config/entity';
-import type { EntityInformation, EntityState } from '@type/room';
+import type { BadgeConfig, StateConfig } from '@type/config/entity';
+import type { EntityState } from '@type/room';
import { expect } from 'chai';
import { html, nothing, type TemplateResult } from 'lit';
import { stub } from 'sinon';
@@ -20,44 +15,22 @@ import { stub } from 'sinon';
describe('badge.ts', () => {
let element: Badge;
let mockHass: HomeAssistant;
- let getStateStub: sinon.SinonStub;
+ let mockEntityState: EntityState;
let getMatchingBadgeStateStub: sinon.SinonStub;
let renderTileBadgeStub: sinon.SinonStub;
let stylesToHostCssStub: sinon.SinonStub;
- const mockEntityState: EntityState = createStateEntity(
- 'light',
- 'living_room',
- 'on',
- {
- friendly_name: 'Living Room Light',
- },
- );
-
- const mockEntityConfig: EntityConfig = {
- entity_id: 'light.living_room',
- icon: 'mdi:lightbulb',
- };
-
- const mockEntity: EntityInformation = {
- config: mockEntityConfig,
- state: mockEntityState,
- };
-
const mockBadgeConfig: BadgeConfig = {
+ entity_id: 'light.living_room',
position: 'top_right',
mode: 'show_always',
};
beforeEach(() => {
- // Register custom element if not already registered
- if (!customElements.get('room-summary-badge')) {
- customElements.define('room-summary-badge', Badge);
- }
+ mockEntityState = createStateEntity('light', 'living_room', 'on', {
+ friendly_name: 'Living Room Light',
+ });
- getStateStub = stub(stateRetrieverModule, 'getState').returns(
- mockEntityState,
- );
getMatchingBadgeStateStub = stub(
badgeStateModule,
'getMatchingBadgeState',
@@ -79,20 +52,20 @@ describe('badge.ts', () => {
element = new Badge();
element.config = mockBadgeConfig;
- element.entity = mockEntity;
+ element.hass = mockHass;
+ // Badge gets state from SubscribeEntityStateMixin; set directly for unit tests
+ element['_subscribedEntityState'] = mockEntityState;
});
afterEach(() => {
- getStateStub.restore();
getMatchingBadgeStateStub.restore();
renderTileBadgeStub.restore();
stylesToHostCssStub.restore();
});
- describe('properties', () => {
- it('should have correct property types', () => {
- expect(element.config).to.equal(mockBadgeConfig);
- expect(element.entity).to.equal(mockEntity);
+ describe('config and properties', () => {
+ it('should store config and set position from config', () => {
+ expect(element['_config']).to.equal(mockBadgeConfig);
expect(element.position).to.equal('top-right');
});
@@ -104,124 +77,41 @@ describe('badge.ts', () => {
const newElement = new Badge();
expect(newElement.position).to.equal('top-right');
});
- });
-
- describe('hass setter', () => {
- it('should set internal hass and update entity', () => {
- element.hass = mockHass;
-
- expect(element['_hass']).to.equal(mockHass);
- expect(element['_entity']).to.exist;
- expect(element['_entity']?.config).to.equal(mockEntityConfig);
- expect(element['_entity']?.state).to.equal(mockEntityState);
- });
- it('should use parent entity when config.entity_id is not set', () => {
- element.config = {
- ...mockBadgeConfig,
- entity_id: undefined,
- };
- element.hass = mockHass;
-
- expect(getStateStub.called).to.be.false;
- expect(element['_entity']?.state).to.equal(mockEntityState);
- });
-
- it('should use config.entity_id when set', () => {
- const otherEntityState = createStateEntity(
- 'sensor',
- 'temperature',
- '25',
- {
- unit_of_measurement: '°C',
- },
- );
- getStateStub.returns(otherEntityState);
-
- element.config = {
- ...mockBadgeConfig,
- entity_id: 'sensor.temperature',
- };
- element.hass = mockHass;
-
- expect(getStateStub.calledWith(mockHass.states, 'sensor.temperature')).to
- .be.true;
- expect(element['_entity']?.state).to.equal(otherEntityState);
- expect(element['_entity']?.config).to.equal(mockEntityConfig);
+ it('should set entityId from config.entity_id', () => {
+ element.config = { ...mockBadgeConfig, entity_id: 'sensor.temp' };
+ expect(element['entityId']).to.equal('sensor.temp');
});
it('should convert position underscores to hyphens', () => {
- element.config = {
- ...mockBadgeConfig,
- position: 'top_left',
- };
- element.hass = mockHass;
-
+ element.config = { ...mockBadgeConfig, position: 'top_left' };
expect(element.position).to.equal('top-left');
});
-
- it('should default to top_right position when not specified', () => {
- element.config = {
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- expect(element.position).to.equal('top-right');
- });
-
- it('should handle all position values', () => {
- const positions: Array<
- 'top_right' | 'top_left' | 'bottom_right' | 'bottom_left'
- > = ['top_right', 'top_left', 'bottom_right', 'bottom_left'];
-
- positions.forEach((pos) => {
- element.config = {
- ...mockBadgeConfig,
- position: pos,
- };
- element.hass = mockHass;
- expect(element.position).to.equal(pos.replace(/_/g, '-'));
- });
- });
});
describe('render', () => {
- beforeEach(() => {
- element.hass = mockHass;
- });
-
- it('should render nothing when entity is not set', () => {
- element['_entity'] = undefined;
+ it('should render nothing when hass is not set', () => {
+ element.hass = undefined as any;
expect(element.render()).to.equal(nothing);
});
- it('should render nothing when hass is not set', () => {
- element['_hass'] = undefined as any;
+ it('should render nothing when _subscribedEntityState is not set', () => {
+ element['_subscribedEntityState'] = undefined;
expect(element.render()).to.equal(nothing);
});
describe('homeassistant mode', () => {
it('should use renderTileBadge when mode is homeassistant', () => {
- element.config = {
- ...mockBadgeConfig,
- mode: 'homeassistant',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'homeassistant' };
const result = element.render();
expect(result).to.not.equal(nothing);
- expect(renderTileBadgeStub.called).to.be.true;
expect(renderTileBadgeStub.calledWith(mockEntityState, mockHass)).to.be
.true;
});
it('should not call getMatchingBadgeState in homeassistant mode', () => {
- element.config = {
- ...mockBadgeConfig,
- mode: 'homeassistant',
- };
- element.hass = mockHass;
-
+ element.config = { ...mockBadgeConfig, mode: 'homeassistant' };
element.render();
expect(getMatchingBadgeStateStub.called).to.be.false;
});
@@ -230,15 +120,16 @@ describe('badge.ts', () => {
describe('if_match mode', () => {
it('should render nothing when no matching state is found', () => {
getMatchingBadgeStateStub.returns(undefined);
- element.config = {
- ...mockBadgeConfig,
- mode: 'if_match',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'if_match' };
const result = element.render();
expect(result).to.equal(nothing);
- expect(getMatchingBadgeStateStub.called).to.be.true;
+ expect(
+ getMatchingBadgeStateStub.calledWith(
+ mockEntityState,
+ element['_config'],
+ ),
+ ).to.be.true;
});
it('should render badge when matching state is found', () => {
@@ -248,27 +139,17 @@ describe('badge.ts', () => {
icon: 'mdi:light-on',
};
getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'if_match',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'if_match' };
const result = element.render();
expect(result).to.not.equal(nothing);
- expect(getMatchingBadgeStateStub.called).to.be.true;
});
});
describe('show_always mode', () => {
it('should render badge even when no matching state', () => {
getMatchingBadgeStateStub.returns(undefined);
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
const result = element.render();
expect(result).to.not.equal(nothing);
@@ -281,24 +162,7 @@ describe('badge.ts', () => {
icon: 'mdi:light-on',
};
getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- const result = element.render();
- expect(result).to.not.equal(nothing);
- });
- });
-
- describe('default mode (show_always)', () => {
- it('should render badge when mode is not specified', () => {
- element.config = {
- position: 'top_right',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
const result = element.render();
expect(result).to.not.equal(nothing);
@@ -306,24 +170,18 @@ describe('badge.ts', () => {
});
describe('badge rendering', () => {
- it('should render ha-tile-badge with correct properties', async () => {
+ it('should render ha-tile-badge with icon_color from matching state', async () => {
const matchingState: StateConfig = {
state: 'on',
icon_color: 'yellow',
icon: 'mdi:light-on',
};
getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
const result = element.render() as TemplateResult;
const el = await fixture(result);
- // fixture() may return the root element or wrap it in a container
const tileBadge = (
el.tagName.toLowerCase() === 'ha-tile-badge'
? el
@@ -342,12 +200,7 @@ describe('badge.ts', () => {
icon: 'mdi:light-on',
};
getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
const result = element.render() as TemplateResult;
const el = await fixture(result);
@@ -358,42 +211,6 @@ describe('badge.ts', () => {
expect((stateIcon as any).stateObj).to.equal(mockEntityState);
expect((stateIcon as any).icon).to.equal('mdi:light-on');
});
-
- it('should use entity config icon when matching state has no icon', async () => {
- const matchingState: StateConfig = {
- state: 'on',
- icon_color: 'yellow',
- };
- getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- const result = element.render() as TemplateResult;
- const el = await fixture(result);
-
- const stateIcon = el.querySelector('ha-state-icon');
- expect((stateIcon as any).icon).to.equal('mdi:lightbulb');
- });
-
- it('should use entity config icon when no matching state', async () => {
- getMatchingBadgeStateStub.returns(undefined);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- const result = element.render() as TemplateResult;
- const el = await fixture(result);
-
- const stateIcon = el.querySelector('ha-state-icon');
- expect((stateIcon as any).icon).to.equal('mdi:lightbulb');
- });
});
describe('styles handling', () => {
@@ -402,21 +219,13 @@ describe('badge.ts', () => {
state: 'on',
icon_color: 'yellow',
icon: 'mdi:light-on',
- styles: {
- '--custom-property': 'value',
- },
+ styles: { '--custom-property': 'value' },
};
getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
element.render();
- expect(stylesToHostCssStub.called).to.be.true;
expect(stylesToHostCssStub.calledWith(matchingState.styles)).to.be.true;
});
@@ -426,200 +235,24 @@ describe('badge.ts', () => {
icon_color: 'yellow',
};
getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- element.render();
-
- expect(stylesToHostCssStub.called).to.be.false;
- });
-
- it('should not call stylesToHostCss when no matching state', () => {
- getMatchingBadgeStateStub.returns(undefined);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
element.render();
expect(stylesToHostCssStub.called).to.be.false;
});
});
-
- describe('icon color handling', () => {
- it('should set background color from matching state', async () => {
- const matchingState: StateConfig = {
- state: 'on',
- icon_color: 'red',
- };
- getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- const result = element.render() as TemplateResult;
- const el = await fixture(result);
-
- // fixture() may return the root element or wrap it in a container
- const tileBadge = (
- el.tagName.toLowerCase() === 'ha-tile-badge'
- ? el
- : el.querySelector('ha-tile-badge')
- ) as HTMLElement;
- expect(
- tileBadge?.style.getPropertyValue('--tile-badge-background-color'),
- ).to.equal('red');
- });
-
- it('should handle undefined icon_color gracefully', async () => {
- const matchingState: StateConfig = {
- state: 'on',
- };
- getMatchingBadgeStateStub.returns(matchingState);
-
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- const result = element.render() as TemplateResult;
- const el = await fixture(result);
-
- // fixture() may return the root element or wrap it in a container
- const tileBadge =
- el.tagName.toLowerCase() === 'ha-tile-badge'
- ? el
- : el.querySelector('ha-tile-badge');
- expect(tileBadge).to.exist;
- // Should still render even without icon_color
- });
- });
});
- describe('edge cases', () => {
- beforeEach(() => {
- element.hass = mockHass;
- });
-
- it('should handle entity with undefined state', () => {
- element.entity = {
- ...mockEntity,
- state: undefined,
- };
- element.hass = mockHass;
-
- // Should still set _entity but render will return nothing
- expect(element['_entity']?.state).to.be.undefined;
- expect(element.render()).to.equal(nothing);
- });
-
- it('should handle config without mode', () => {
- element.config = {
- position: 'top_right',
- };
- element.hass = mockHass;
-
- const result = element.render();
- expect(result).to.not.equal(nothing);
- });
-
- it('should handle config without position', () => {
- element.config = {
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- expect(element.position).to.equal('top-right');
- const result = element.render();
- expect(result).to.not.equal(nothing);
- });
-
- it('should handle entity config without icon', () => {
- const entityWithoutIcon: EntityInformation = {
- config: {
- entity_id: 'light.living_room',
- },
- state: mockEntityState,
- };
- element.entity = entityWithoutIcon;
- element.hass = mockHass;
-
- const result = element.render() as TemplateResult;
- expect(result).to.not.equal(nothing);
- });
-
- it('should handle getState returning undefined for custom entity_id', () => {
- getStateStub.returns(undefined);
-
- element.config = {
- ...mockBadgeConfig,
- entity_id: 'sensor.nonexistent',
- };
- element.hass = mockHass;
-
- // Should use undefined state from getState
- expect(element['_entity']?.state).to.be.undefined;
- expect(element.render()).to.equal(nothing);
- });
- });
-
- describe('integration', () => {
- beforeEach(() => {
- element.hass = mockHass;
- });
-
- it('should call getMatchingBadgeState with correct parameters', () => {
- element.config = {
- ...mockBadgeConfig,
- mode: 'show_always',
- };
- element.hass = mockHass;
-
- element.render();
-
- expect(getMatchingBadgeStateStub.called).to.be.true;
- expect(
- getMatchingBadgeStateStub.calledWith(
- element['_entity'],
- mockBadgeConfig,
- ),
- ).to.be.true;
- });
-
- it('should use custom entity when config.entity_id is set', () => {
- const customEntityState = createStateEntity(
- 'sensor',
- 'temperature',
- '25',
- );
- getStateStub.returns(customEntityState);
-
- element.config = {
- ...mockBadgeConfig,
- entity_id: 'sensor.temperature',
- };
- element.hass = mockHass;
-
+ describe('getMatchingBadgeState integration', () => {
+ it('should call getMatchingBadgeState with state and config', () => {
+ element.config = { ...mockBadgeConfig, mode: 'show_always' };
element.render();
expect(
getMatchingBadgeStateStub.calledWith(
- {
- config: mockEntityConfig,
- state: customEntityState,
- },
- element.config,
+ mockEntityState,
+ element['_config'],
),
).to.be.true;
});
diff --git a/test/cards/components/room-state-icon.spec.ts b/test/cards/components/room-state-icon.spec.ts
index ccb61a5f..5f19b74f 100644
--- a/test/cards/components/room-state-icon.spec.ts
+++ b/test/cards/components/room-state-icon.spec.ts
@@ -313,13 +313,8 @@ describe('room-state-icon.ts', () => {
element.render();
expect(renderBadgeElementsStub.called).to.be.true;
- expect(
- renderBadgeElementsStub.calledWith(
- mockEntity.config.badges,
- mockEntity,
- mockHass,
- ),
- ).to.be.true;
+ expect(renderBadgeElementsStub.calledWith(mockEntity, mockHass)).to.be
+ .true;
});
it('should show entity label when show_entity_labels feature is enabled', async () => {
diff --git a/test/cards/mixins/hass-update-mixin.spec.ts b/test/cards/mixins/hass-update-mixin.spec.ts
index dd1fd9af..01a941d0 100644
--- a/test/cards/mixins/hass-update-mixin.spec.ts
+++ b/test/cards/mixins/hass-update-mixin.spec.ts
@@ -27,12 +27,6 @@ describe('HassUpdateMixin', () => {
} as HomeAssistant;
});
- afterEach(() => {
- if (element.parentNode) {
- element.parentNode.removeChild(element);
- }
- });
-
it('should have hass property', () => {
expect(element).to.have.property('hass');
expect(element.hass).to.be.undefined;
diff --git a/test/cards/mixins/subscribe-entity-state-mixin.spec.ts b/test/cards/mixins/subscribe-entity-state-mixin.spec.ts
new file mode 100644
index 00000000..6d21021a
--- /dev/null
+++ b/test/cards/mixins/subscribe-entity-state-mixin.spec.ts
@@ -0,0 +1,167 @@
+import { SubscribeEntityStateMixin } from '@cards/mixins/subscribe-entity-state-mixin';
+import * as subscribeTrigger from '@delegates/entities/subscribe-trigger';
+import type { HomeAssistant } from '@hass/types';
+import { expect } from 'chai';
+import { LitElement } from 'lit';
+import { type SinonStub, stub } from 'sinon';
+
+describe('SubscribeEntityStateMixin', () => {
+ let TestElement: ReturnType;
+ let element: InstanceType;
+ let hass: HomeAssistant;
+ let subscribeStub: SinonStub;
+ let unsubscribeSpy: SinonStub;
+ let elementCounter = 0;
+
+ beforeEach(() => {
+ unsubscribeSpy = stub();
+ subscribeStub = stub(subscribeTrigger, 'subscribeEntityState').resolves(
+ unsubscribeSpy,
+ );
+
+ const elementName = `test-sub-entity-${elementCounter++}`;
+ TestElement = SubscribeEntityStateMixin(LitElement);
+
+ if (!customElements.get(elementName)) {
+ customElements.define(elementName, TestElement);
+ }
+
+ element = new TestElement();
+ hass = {
+ language: 'en',
+ localize: (key: string) => key,
+ states: {
+ 'light.bedroom': {
+ entity_id: 'light.bedroom',
+ state: 'on',
+ attributes: { friendly_name: 'Bedroom Light' },
+ },
+ },
+ } as unknown as HomeAssistant;
+ });
+
+ afterEach(() => {
+ subscribeStub.restore();
+ });
+
+ it('should have _subscribedEntityState undefined initially', () => {
+ expect(element['_subscribedEntityState']).to.be.undefined;
+ });
+
+ it('should subscribe when connected with entityId and hass set', async () => {
+ element.hass = hass;
+ element['entityId'] = 'light.bedroom';
+
+ element.connectedCallback();
+
+ expect(subscribeStub.calledOnce).to.be.true;
+ expect(subscribeStub.firstCall.args[1]).to.equal('light.bedroom');
+ });
+
+ it('should set initial state from hass.states on subscribe', () => {
+ element.hass = hass;
+ element['entityId'] = 'light.bedroom';
+
+ element.connectedCallback();
+
+ expect(element['_subscribedEntityState']).to.deep.equal({
+ entity_id: 'light.bedroom',
+ state: 'on',
+ attributes: { friendly_name: 'Bedroom Light' },
+ domain: 'light',
+ });
+ });
+
+ it('should not subscribe without entityId', () => {
+ element.hass = hass;
+
+ element.connectedCallback();
+
+ expect(subscribeStub.called).to.be.false;
+ });
+
+ it('should not subscribe without hass', () => {
+ element['entityId'] = 'light.bedroom';
+
+ element.connectedCallback();
+
+ expect(subscribeStub.called).to.be.false;
+ });
+
+ it('should unsubscribe on disconnectedCallback', async () => {
+ element.hass = hass;
+ element['entityId'] = 'light.bedroom';
+
+ element.connectedCallback();
+
+ // Wait for the subscribe promise to resolve
+ await Promise.resolve();
+
+ element.disconnectedCallback();
+
+ expect(unsubscribeSpy.calledOnce).to.be.true;
+ });
+
+ it('should update state when trigger callback fires with changed state', () => {
+ element.hass = hass;
+ element['entityId'] = 'light.bedroom';
+
+ element.connectedCallback();
+
+ // Get the onChange callback passed to subscribeEntityState
+ const onChange = subscribeStub.firstCall.args[2];
+
+ onChange({
+ variables: {
+ trigger: {
+ from_state: {
+ entity_id: 'light.bedroom',
+ state: 'on',
+ attributes: { friendly_name: 'Bedroom Light' },
+ },
+ to_state: {
+ entity_id: 'light.bedroom',
+ state: 'off',
+ attributes: { friendly_name: 'Bedroom Light' },
+ },
+ },
+ },
+ });
+
+ expect(element['_subscribedEntityState']).to.deep.equal({
+ entity_id: 'light.bedroom',
+ state: 'off',
+ attributes: { friendly_name: 'Bedroom Light' },
+ domain: 'light',
+ });
+ });
+
+ it('should not update state when from_state equals to_state', () => {
+ element.hass = hass;
+ element['entityId'] = 'light.bedroom';
+
+ element.connectedCallback();
+
+ const initialState = element['_subscribedEntityState'];
+ const onChange = subscribeStub.firstCall.args[2];
+
+ onChange({
+ variables: {
+ trigger: {
+ from_state: {
+ entity_id: 'light.bedroom',
+ state: 'on',
+ attributes: { friendly_name: 'Bedroom Light' },
+ },
+ to_state: {
+ entity_id: 'light.bedroom',
+ state: 'on',
+ attributes: { friendly_name: 'Bedroom Light' },
+ },
+ },
+ },
+ });
+
+ expect(element['_subscribedEntityState']).to.deep.equal(initialState);
+ });
+});
diff --git a/test/delegates/checks/occupancy.spec.ts b/test/delegates/checks/occupancy.spec.ts
index acdbc7ee..1e48e29c 100644
--- a/test/delegates/checks/occupancy.spec.ts
+++ b/test/delegates/checks/occupancy.spec.ts
@@ -145,6 +145,23 @@ describe('occupancy.ts', () => {
expect(result['--occupancy-icon-color']).to.equal('#00ff00');
});
+ it('should resolve HA color names and ones with spaces to CSS variables', () => {
+ const config: AlarmConfig = {
+ entities: ['binary_sensor.motion_1'],
+ card_border_color: 'deep-purple',
+ icon_color: 'accent',
+ };
+ const result = getOccupancyCssVars(true, config);
+
+ expect(result['--occupancy-card-border']).to.equal(
+ '3px solid var(--deep-purple-color)',
+ );
+ expect(result['--occupancy-card-border-color']).to.equal(
+ 'var(--deep-purple-color)',
+ );
+ expect(result['--occupancy-icon-color']).to.equal('var(--accent-color)');
+ });
+
it('should disable card border styles when disabled_card_styles option is set', () => {
const config: AlarmConfig = {
entities: ['binary_sensor.motion_1'],
diff --git a/test/delegates/entities/subscribe-trigger.spec.ts b/test/delegates/entities/subscribe-trigger.spec.ts
new file mode 100644
index 00000000..6401e6c5
--- /dev/null
+++ b/test/delegates/entities/subscribe-trigger.spec.ts
@@ -0,0 +1,33 @@
+import type { HomeAssistant } from '@hass/types';
+import { expect } from 'chai';
+import { subscribeEntityState } from '../../../src/delegates/entities/subscribe-trigger';
+
+describe('subscribe-trigger.ts', () => {
+ describe('subscribeEntityState', () => {
+ it('calls subscribeMessage with state trigger when connection available', async () => {
+ const unsubscribeReal = () => {};
+ const subscribeMessage = (
+ callback: (r: unknown) => void,
+ msg: unknown,
+ ) => {
+ expect(msg).to.deep.equal({
+ type: 'subscribe_trigger',
+ trigger: { platform: 'state', entity_id: 'light.test' },
+ });
+ return Promise.resolve(unsubscribeReal);
+ };
+ const hass = {
+ connection: { subscribeMessage },
+ } as HomeAssistant & {
+ connection: { subscribeMessage: typeof subscribeMessage };
+ };
+ const onChange = () => {};
+ const unsubscribe = await subscribeEntityState(
+ hass,
+ 'light.test',
+ onChange,
+ );
+ expect(unsubscribe).to.equal(unsubscribeReal);
+ });
+ });
+});
diff --git a/test/delegates/utils/badge-state.spec.ts b/test/delegates/utils/badge-state.spec.ts
index d25e2301..8a882a1b 100644
--- a/test/delegates/utils/badge-state.spec.ts
+++ b/test/delegates/utils/badge-state.spec.ts
@@ -1,19 +1,14 @@
import { getMatchingBadgeState } from '@delegates/utils/badge-state';
import { createStateEntity } from '@test/test-helpers';
import type { BadgeConfig, StateConfig } from '@type/config/entity';
-import type { EntityInformation } from '@type/room';
+import type { EntityState } from '@type/room';
import { expect } from 'chai';
describe('badge-state.ts', () => {
const createEntity = (
state: string,
attributes: Record = {},
- ): EntityInformation => ({
- config: {
- entity_id: 'light.test',
- },
- state: createStateEntity('light', 'test', state, attributes),
- });
+ ): EntityState => createStateEntity('light', 'test', state, attributes);
const createBadge = (states?: StateConfig[]): BadgeConfig => ({
states,
@@ -28,14 +23,13 @@ describe('badge-state.ts', () => {
});
it('should return undefined when entity state is undefined', () => {
- const entity: EntityInformation = {
- config: { entity_id: 'light.test' },
- state: undefined,
- };
const badge = createBadge([
{ state: 'on', icon_color: 'yellow', icon: 'mdi:light-on' },
]);
- const result = getMatchingBadgeState(entity, badge);
+ const result = getMatchingBadgeState(
+ undefined as unknown as EntityState,
+ badge,
+ );
expect(result).to.be.undefined;
});
@@ -163,7 +157,12 @@ describe('badge-state.ts', () => {
it('should evaluate states in order - eq before ne', () => {
const states: StateConfig[] = [
- { state: 'ok', icon_color: 'green', icon: 'mdi:check', operator: 'eq' },
+ {
+ state: 'ok',
+ icon_color: 'green',
+ icon: 'mdi:check',
+ operator: 'eq',
+ },
{ state: 'ok', icon_color: 'red', icon: 'mdi:alert', operator: 'ne' },
];
const entity = createEntity('ok');
@@ -175,7 +174,12 @@ describe('badge-state.ts', () => {
it('should evaluate states in order - ne matches when eq does not', () => {
const states: StateConfig[] = [
- { state: 'ok', icon_color: 'green', icon: 'mdi:check', operator: 'eq' },
+ {
+ state: 'ok',
+ icon_color: 'green',
+ icon: 'mdi:check',
+ operator: 'eq',
+ },
{ state: 'ok', icon_color: 'red', icon: 'mdi:alert', operator: 'ne' },
];
const entity = createEntity('error');
diff --git a/test/delegates/utils/sensor-sifter.spec.ts b/test/delegates/utils/sensor-sifter.spec.ts
new file mode 100644
index 00000000..4b4b2cef
--- /dev/null
+++ b/test/delegates/utils/sensor-sifter.spec.ts
@@ -0,0 +1,277 @@
+import { probablyClassSensorUsersMadeThisComplex } from '@delegates/utils/sensor-sifter';
+import type { AreaRegistryEntry } from '@hass/data/area/area_registry';
+import { createStateEntity as e } from '@test/test-helpers';
+import type { Config } from '@type/config';
+import { expect } from 'chai';
+
+describe('sensor-sifter.ts', () => {
+ const defaultConfig: Config = { area: 'living_room' };
+ const defaultClasses = ['temperature', 'humidity', 'illuminance'];
+
+ const area: AreaRegistryEntry = {
+ area_id: 'living_room',
+ name: 'Living Room',
+ icon: 'mdi:sofa',
+ picture: null,
+ };
+
+ describe('exclude_default_entities', () => {
+ it('should return false when exclude_default_entities is enabled', () => {
+ const config: Config = {
+ ...defaultConfig,
+ features: ['exclude_default_entities'],
+ };
+ const state = e('sensor', 'temp', '72', { device_class: 'temperature' });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ config,
+ area,
+ defaultClasses,
+ ),
+ ).to.be.false;
+ });
+ });
+
+ describe('domain and device class filtering', () => {
+ it('should return false for non-sensor domains', () => {
+ const state = e('binary_sensor', 'motion', 'on', {
+ device_class: 'motion',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ area,
+ defaultClasses,
+ ),
+ ).to.be.false;
+ });
+
+ it('should return false when device_class is missing', () => {
+ const state = e('sensor', 'custom', '42');
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ area,
+ defaultClasses,
+ ),
+ ).to.be.false;
+ });
+
+ it('should return false when device_class is not in sensorClasses', () => {
+ const state = e('sensor', 'pressure', '1013', {
+ device_class: 'pressure',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ area,
+ defaultClasses,
+ ),
+ ).to.be.false;
+ });
+
+ it('should return true for a sensor with a matching device_class', () => {
+ const state = e('sensor', 'temp', '72', {
+ device_class: 'temperature',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ area,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+
+ it('should return true for illuminance sensor', () => {
+ const state = e('sensor', 'lux', '500', {
+ device_class: 'illuminance',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ area,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+ });
+
+ describe('area default sensor logic', () => {
+ const areaWithDefaults: AreaRegistryEntry = {
+ ...area,
+ temperature_entity_id: 'sensor.area_temp',
+ humidity_entity_id: 'sensor.area_humidity',
+ };
+
+ it('should return true for the area default temperature sensor', () => {
+ const state = e('sensor', 'area_temp', '72', {
+ device_class: 'temperature',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaWithDefaults,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+
+ it('should return true for the area default humidity sensor', () => {
+ const state = e('sensor', 'area_humidity', '45', {
+ device_class: 'humidity',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaWithDefaults,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+
+ it('should return false for a non-default temperature sensor when area has a default', () => {
+ const state = e('sensor', 'other_temp', '68', {
+ device_class: 'temperature',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaWithDefaults,
+ defaultClasses,
+ ),
+ ).to.be.false;
+ });
+
+ it('should return false for a non-default humidity sensor when area has a default', () => {
+ const state = e('sensor', 'other_humidity', '50', {
+ device_class: 'humidity',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaWithDefaults,
+ defaultClasses,
+ ),
+ ).to.be.false;
+ });
+
+ it('should still return true for illuminance when area has temp/humidity defaults', () => {
+ const state = e('sensor', 'lux', '500', {
+ device_class: 'illuminance',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaWithDefaults,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+ });
+
+ describe('partial area defaults', () => {
+ it('should allow non-default temp sensors when area only has humidity default', () => {
+ const areaHumidityOnly: AreaRegistryEntry = {
+ ...area,
+ humidity_entity_id: 'sensor.area_humidity',
+ };
+ const state = e('sensor', 'any_temp', '72', {
+ device_class: 'temperature',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaHumidityOnly,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+
+ it('should allow non-default humidity sensors when area only has temp default', () => {
+ const areaTempOnly: AreaRegistryEntry = {
+ ...area,
+ temperature_entity_id: 'sensor.area_temp',
+ };
+ const state = e('sensor', 'any_humidity', '45', {
+ device_class: 'humidity',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ areaTempOnly,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+ });
+
+ describe('undefined area', () => {
+ it('should return true for matching sensors when area is undefined', () => {
+ const state = e('sensor', 'temp', '72', {
+ device_class: 'temperature',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(
+ state,
+ defaultConfig,
+ undefined,
+ defaultClasses,
+ ),
+ ).to.be.true;
+ });
+ });
+
+ describe('custom sensor classes', () => {
+ it('should respect a custom sensorClasses list', () => {
+ const state = e('sensor', 'pressure', '1013', {
+ device_class: 'pressure',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(state, defaultConfig, area, [
+ 'pressure',
+ ]),
+ ).to.be.true;
+ });
+
+ it('should reject temperature when not in custom sensorClasses', () => {
+ const state = e('sensor', 'temp', '72', {
+ device_class: 'temperature',
+ });
+
+ expect(
+ probablyClassSensorUsersMadeThisComplex(state, defaultConfig, area, [
+ 'pressure',
+ ]),
+ ).to.be.false;
+ });
+ });
+});
diff --git a/test/html/badge-squad.spec.ts b/test/html/badge-squad.spec.ts
index da24cfb1..fa3ff531 100644
--- a/test/html/badge-squad.spec.ts
+++ b/test/html/badge-squad.spec.ts
@@ -1,7 +1,6 @@
import type { HomeAssistant } from '@hass/types';
import { renderBadgeElements } from '@html/badge-squad';
import { createStateEntity } from '@test/test-helpers';
-import type { BadgeConfig } from '@type/config/entity';
import type { EntityInformation } from '@type/room';
import { expect } from 'chai';
@@ -26,32 +25,20 @@ describe('badge-squad.ts', () => {
});
describe('renderBadgeElements', () => {
- it('should return empty array when badges is undefined', () => {
- const result = renderBadgeElements(undefined, mockEntity, mockHass);
- expect(result).to.be.an('array');
- expect(result).to.have.length(0);
+ it('should return undefined when entity.config.badges is undefined', () => {
+ const result = renderBadgeElements(mockEntity, mockHass);
+ expect(result).to.be.undefined;
});
- it('should return empty array when badges is empty', () => {
- const result = renderBadgeElements([], mockEntity, mockHass);
+ it('should return empty array when entity.config.badges is empty', () => {
+ mockEntity.config.badges = [];
+ const result = renderBadgeElements(mockEntity, mockHass);
expect(result).to.be.an('array');
expect(result).to.have.length(0);
});
- it('should render single badge', () => {
- const badges: BadgeConfig[] = [
- {
- position: 'top_right',
- mode: 'show_always',
- },
- ];
- const result = renderBadgeElements(badges, mockEntity, mockHass);
- expect(result).to.have.length(1);
- expect(result[0]).to.be.instanceOf(Object);
- });
-
it('should limit badges to maximum of 4', () => {
- const badges: BadgeConfig[] = [
+ mockEntity.config.badges = [
{ position: 'top_right' },
{ position: 'top_left' },
{ position: 'bottom_right' },
@@ -59,34 +46,37 @@ describe('badge-squad.ts', () => {
{ position: 'top_right' }, // 5th badge should be ignored
{ position: 'top_left' }, // 6th badge should be ignored
];
- const result = renderBadgeElements(badges, mockEntity, mockHass);
+ const result = renderBadgeElements(mockEntity, mockHass);
expect(result).to.have.length(4);
});
- it('should render all badges when count is exactly 4', () => {
- const badges: BadgeConfig[] = [
- { position: 'top_right' },
- { position: 'top_left' },
- { position: 'bottom_right' },
- { position: 'bottom_left' },
+ it('should fall back to entity.config.entity_id when badge has no entity_id', () => {
+ mockEntity.config.badges = [
+ {
+ position: 'top_right',
+ mode: 'show_always',
+ },
];
- const result = renderBadgeElements(badges, mockEntity, mockHass);
- expect(result).to.have.length(4);
+ const result = renderBadgeElements(mockEntity, mockHass);
+ expect(result).to.have.length(1);
+ const badgeConfig = result?.[0]?.values?.[1] as { entity_id?: string };
+ expect(badgeConfig?.entity_id).to.equal('light.test');
});
- it('should render badges with correct properties', () => {
- const badges: BadgeConfig[] = [
+ it('should render badges with correct template structure', () => {
+ mockEntity.config.badges = [
{
position: 'top_right',
mode: 'show_always',
entity_id: 'sensor.test',
},
];
- const result = renderBadgeElements(badges, mockEntity, mockHass);
+ const result = renderBadgeElements(mockEntity, mockHass);
expect(result).to.have.length(1);
- // Verify it's a template result (has strings and values)
- expect(result[0]).to.have.property('strings');
- expect(result[0]).to.have.property('values');
+ expect(result![0]).to.have.property('strings');
+ expect(result![0]).to.have.property('values');
+ const badgeConfig = result?.[0]?.values?.[1] as { entity_id?: string };
+ expect(badgeConfig?.entity_id).to.equal('sensor.test');
});
});
});
diff --git a/test/index.spec.ts b/test/index.spec.ts
index 821f1d73..08bc7ddd 100644
--- a/test/index.spec.ts
+++ b/test/index.spec.ts
@@ -92,7 +92,8 @@ describe('index.ts', () => {
name: 'Existing Card',
description: 'Existing Card Description',
preview: true,
- documentationURL: 'https://github.com/homeassistant-extras/room-summary-card',
+ documentationURL:
+ 'https://github.com/homeassistant-extras/room-summary-card',
},
];
@@ -104,7 +105,8 @@ describe('index.ts', () => {
name: 'Existing Card',
description: 'Existing Card Description',
preview: true,
- documentationURL: 'https://github.com/homeassistant-extras/room-summary-card',
+ documentationURL:
+ 'https://github.com/homeassistant-extras/room-summary-card',
});
});
diff --git a/test/theme/threshold-color.spec.ts b/test/theme/threshold-color.spec.ts
index 63cd8925..40ad0f0c 100644
--- a/test/theme/threshold-color.spec.ts
+++ b/test/theme/threshold-color.spec.ts
@@ -801,7 +801,6 @@ describe('threshold-color.ts', () => {
});
});
-
describe('getEntityLabel', () => {
const createEntity = (
state: string,
diff --git a/test/util/comparison-utils.spec.ts b/test/util/comparison-utils.spec.ts
index f5aeea60..96815823 100644
--- a/test/util/comparison-utils.spec.ts
+++ b/test/util/comparison-utils.spec.ts
@@ -1,5 +1,5 @@
-import { meetsStateCondition, meetsThreshold } from '@util/comparison-utils';
import type { ThresholdConfig } from '@type/config/entity';
+import { meetsStateCondition, meetsThreshold } from '@util/comparison-utils';
import { expect } from 'chai';
describe('comparison-utils.ts', () => {
diff --git a/test/util/debug.spec.ts b/test/util/debug.spec.ts
index 4b33e758..f92dab78 100644
--- a/test/util/debug.spec.ts
+++ b/test/util/debug.spec.ts
@@ -1,40 +1,92 @@
-import * as featureModule from '@config/feature';
import type { Config } from '@type/config';
import { expect } from 'chai';
import { stub } from 'sinon';
import { d } from '../../src/util/debug';
describe('debug.ts', () => {
- let hasFeatureStub: sinon.SinonStub;
+ it('should log when config.debug exists', () => {
+ const config: Config = { area: '', debug: {} } as Config;
+ const consoleDebugStub = stub(console, 'debug');
+
+ d(config, 'room-summary-card', 'render', 'extra');
+
+ expect(consoleDebugStub.calledOnce).to.be.true;
+ expect(consoleDebugStub.calledWith('[room-summary-card] render', 'extra'))
+ .to.be.true;
+ consoleDebugStub.restore();
+ });
+
+ it('should not log when config.debug is absent', () => {
+ const config: Config = { area: '' } as Config;
+ const consoleDebugStub = stub(console, 'debug');
+
+ d(config, 'room-summary-card', 'render');
+
+ expect(consoleDebugStub.notCalled).to.be.true;
+ consoleDebugStub.restore();
+ });
+
+ it('should not log when config is undefined', () => {
+ const consoleDebugStub = stub(console, 'debug');
- beforeEach(() => {
- hasFeatureStub = stub(featureModule, 'hasFeature');
+ d(undefined, 'room-summary-card', 'render');
+
+ expect(consoleDebugStub.notCalled).to.be.true;
+ consoleDebugStub.restore();
});
- afterEach(() => {
- hasFeatureStub.restore();
+ it('should filter by scope when scope is set', () => {
+ const config: Config = {
+ area: '',
+ debug: { scope: ['room-summary-card'] },
+ } as Config;
+ const consoleDebugStub = stub(console, 'debug');
+
+ d(config, 'room-summary-card', 'render');
+ expect(consoleDebugStub.calledOnce).to.be.true;
+
+ consoleDebugStub.resetHistory();
+ d(config, 'entity-collection', 'render');
+ expect(consoleDebugStub.notCalled).to.be.true;
+
+ consoleDebugStub.restore();
});
- it('should log debug messages when the "debug" feature is enabled', () => {
- const config: Config = {} as Config;
- hasFeatureStub.withArgs(config, 'debug').returns(true);
+ it('should filter by categories when categories is set', () => {
+ const config: Config = {
+ area: '',
+ debug: { categories: ['render'] },
+ } as Config;
const consoleDebugStub = stub(console, 'debug');
- d(config, 'Test message', 123);
+ d(config, 'room-summary-card', 'render');
+ expect(consoleDebugStub.calledOnce).to.be.true;
+
+ consoleDebugStub.resetHistory();
+ d(config, 'room-summary-card', 'set hass');
+ expect(consoleDebugStub.notCalled).to.be.true;
- expect(consoleDebugStub.calledOnceWithExactly('Test message', 123)).to.be
- .true;
consoleDebugStub.restore();
});
- it('should not log debug messages when the "debug" feature is disabled', () => {
- const config: Config = {} as Config;
- hasFeatureStub.withArgs(config, 'debug').returns(false);
+ it('should require both scope and category when both are set', () => {
+ const config: Config = {
+ area: '',
+ debug: { scope: ['room-summary-card'], categories: ['render'] },
+ } as Config;
const consoleDebugStub = stub(console, 'debug');
- d(config, 'Test message', 123);
+ d(config, 'room-summary-card', 'render');
+ expect(consoleDebugStub.calledOnce).to.be.true;
+ consoleDebugStub.resetHistory();
+ d(config, 'entity-collection', 'render');
expect(consoleDebugStub.notCalled).to.be.true;
+
+ consoleDebugStub.resetHistory();
+ d(config, 'room-summary-card', 'set hass');
+ expect(consoleDebugStub.notCalled).to.be.true;
+
consoleDebugStub.restore();
});
});
diff --git a/tsconfig.json b/tsconfig.json
index 6003760b..547681c5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "noEmit": true,
/* Base Options: */
"skipLibCheck": true,
"target": "es2015",
diff --git a/yarn.lock b/yarn.lock
index 6d682d55..6a2b3243 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,10 +2,10 @@
# yarn lockfile v1
-"@acemir/cssom@^0.9.28":
- version "0.9.29"
- resolved "https://registry.yarnpkg.com/@acemir/cssom/-/cssom-0.9.29.tgz#3ae97903c49b388a5ff5d231a7a6d42a32e5b148"
- integrity sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==
+"@acemir/cssom@^0.9.31":
+ version "0.9.31"
+ resolved "https://registry.yarnpkg.com/@acemir/cssom/-/cssom-0.9.31.tgz#bd5337d290fb8be2ac18391f37386bc53778b0bc"
+ integrity sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==
"@ampproject/remapping@^2.2.0":
version "2.3.0"
@@ -15,27 +15,27 @@
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
-"@asamuzakjp/css-color@^4.1.0":
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/@asamuzakjp/css-color/-/css-color-4.1.0.tgz#4c8c6f48ed2e5c1ad9cc1aa23c80d665e56dd458"
- integrity sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==
+"@asamuzakjp/css-color@^4.1.2":
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/@asamuzakjp/css-color/-/css-color-4.1.2.tgz#1123e18b3652ff88fbdd90d61f2e2e44dd8ba28f"
+ integrity sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==
dependencies:
- "@csstools/css-calc" "^2.1.4"
- "@csstools/css-color-parser" "^3.1.0"
- "@csstools/css-parser-algorithms" "^3.0.5"
- "@csstools/css-tokenizer" "^3.0.4"
- lru-cache "^11.2.2"
+ "@csstools/css-calc" "^3.0.0"
+ "@csstools/css-color-parser" "^4.0.1"
+ "@csstools/css-parser-algorithms" "^4.0.0"
+ "@csstools/css-tokenizer" "^4.0.0"
+ lru-cache "^11.2.5"
-"@asamuzakjp/dom-selector@^6.7.6":
- version "6.7.6"
- resolved "https://registry.yarnpkg.com/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz#9cd7671a61a9cb490852ed6a441b3b0950aab945"
- integrity sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==
+"@asamuzakjp/dom-selector@^6.8.1":
+ version "6.8.1"
+ resolved "https://registry.yarnpkg.com/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz#39b20993672b106f7cd9a3a9a465212e87e0bfd1"
+ integrity sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==
dependencies:
"@asamuzakjp/nwsapi" "^2.3.9"
bidi-js "^1.0.3"
css-tree "^3.1.0"
is-potential-custom-element-name "^1.0.1"
- lru-cache "^11.2.4"
+ lru-cache "^11.2.6"
"@asamuzakjp/nwsapi@^2.3.9":
version "2.3.9"
@@ -186,6 +186,13 @@
"@babel/helper-string-parser" "^7.27.1"
"@babel/helper-validator-identifier" "^7.27.1"
+"@bramus/specificity@^2.4.2":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@bramus/specificity/-/specificity-2.4.2.tgz#aa8db8eb173fdee7324f82284833106adeecc648"
+ integrity sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==
+ dependencies:
+ css-tree "^3.0.0"
+
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz"
@@ -193,38 +200,38 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
-"@csstools/color-helpers@^5.1.0":
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.1.0.tgz#106c54c808cabfd1ab4c602d8505ee584c2996ef"
- integrity sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==
+"@csstools/color-helpers@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-6.0.1.tgz#637c08a61bea78be9b602216f47b0fb93c996178"
+ integrity sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==
-"@csstools/css-calc@^2.1.4":
- version "2.1.4"
- resolved "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz"
- integrity sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==
+"@csstools/css-calc@^3.0.0":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-3.1.1.tgz#78b494996dac41a02797dcca18ac3b46d25b3fd7"
+ integrity sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==
-"@csstools/css-color-parser@^3.1.0":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz#4e386af3a99dd36c46fef013cfe4c1c341eed6f0"
- integrity sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==
+"@csstools/css-color-parser@^4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-4.0.1.tgz#c40eac0ad218afb20b91735350270df8454ec307"
+ integrity sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==
dependencies:
- "@csstools/color-helpers" "^5.1.0"
- "@csstools/css-calc" "^2.1.4"
+ "@csstools/color-helpers" "^6.0.1"
+ "@csstools/css-calc" "^3.0.0"
-"@csstools/css-parser-algorithms@^3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz#5755370a9a29abaec5515b43c8b3f2cf9c2e3076"
- integrity sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==
+"@csstools/css-parser-algorithms@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz#e1c65dc09378b42f26a111fca7f7075fc2c26164"
+ integrity sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==
-"@csstools/css-syntax-patches-for-csstree@1.0.14":
- version "1.0.14"
- resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz#96e8bd829dea29da6460ac7568ee922f48ecc382"
- integrity sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==
+"@csstools/css-syntax-patches-for-csstree@^1.0.26":
+ version "1.0.27"
+ resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.27.tgz#47caab710c26b5cfba200c5820b11dba29a2fcc9"
+ integrity sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==
-"@csstools/css-tokenizer@^3.0.4":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3"
- integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==
+"@csstools/css-tokenizer@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz#798a33950d11226a0ebb6acafa60f5594424967f"
+ integrity sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==
"@esm-bundle/chai@^4.3.4-fix.0":
version "4.3.4-fix.0"
@@ -233,10 +240,10 @@
dependencies:
"@types/chai" "^4.2.12"
-"@exodus/bytes@^1.6.0":
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/@exodus/bytes/-/bytes-1.7.0.tgz#0bfe8baefb3843eb28b15eff7fd18edaefff6228"
- integrity sha512-5i+BtvujK/vM07YCGDyz4C4AyDzLmhxHMtM5HpUyPRtJPBdFPsj290ffXW+UXY21/G7GtXeHD2nRmq0T1ShyQQ==
+"@exodus/bytes@^1.11.0", "@exodus/bytes@^1.6.0":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@exodus/bytes/-/bytes-1.14.1.tgz#9b5c29077162a35f1bd25613e0cd3c239f6e7ad8"
+ integrity sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==
"@hapi/bourne@^3.0.0":
version "3.0.0"
@@ -475,101 +482,101 @@
"@types/sinon-chai" "^3.2.3"
chai-a11y-axe "^1.5.0"
-"@parcel/bundler-default@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.16.3.tgz#1f868c6172bf874ad558c69321c5c49d65d62810"
- integrity sha512-zCW2KzMfcEXqpVSU+MbLFMV3mHIzm/7UK1kT8mceuj4UwUScw7Lmjmulc2Ev4hcnwnaAFyaVkyFE5JXA4GKsLQ==
+"@parcel/bundler-default@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.16.4.tgz#e4a273ef224b974eab3981a94873f760ef35184b"
+ integrity sha512-Nb8peNvhfm1+660CLwssWh4weY+Mv6vEGS6GPKqzJmTMw50udi0eS1YuWFzvmhSiu1KsYcUD37mqQ1LuIDtWoA==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/graph" "3.6.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/graph" "3.6.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/cache@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.16.3.tgz#dd65df6a10501478cf44621df08136b41de51098"
- integrity sha512-iWlbdTk9h7yTG1fxpGvftUD7rVbXVQn1+U21BGqFyYxfrd+wgdN624daIG6+eqI6yBuaBTEwH+cb3kaI9sH1ng==
+"@parcel/cache@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.16.4.tgz#54c4d43bad48422acf97cfb7870a780e1c819b7f"
+ integrity sha512-+uCyeElSga2MBbmbXpIj/WVKH7TByCrKaxtHbelfKKIJpYMgEHVjO4cuc7GUfTrUAmRUS8ZGvnX7Etgq6/jQhw==
dependencies:
- "@parcel/fs" "2.16.3"
- "@parcel/logger" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/fs" "2.16.4"
+ "@parcel/logger" "2.16.4"
+ "@parcel/utils" "2.16.4"
lmdb "2.8.5"
-"@parcel/codeframe@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.16.3.tgz#28c580086b154356d3d1e9fe70092ed283df0a0b"
- integrity sha512-oXZx8PUqExnXnAHCLhxulTDeFvTBqPAwJU4AVZwnYFToaQ6nltXWWYaDGUu2f/V3Z17LObWiOROHT7HYXAe62Q==
+"@parcel/codeframe@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.16.4.tgz#7698a6c887588daf75995b75d532ac67d57e7249"
+ integrity sha512-s64aMfOJoPrXhKH+Y98ahX0O8aXWvTR+uNlOaX4yFkpr4FFDnviLcGngDe/Yo4Qq2FJZ0P6dNswbJTUH9EGxkQ==
dependencies:
chalk "^4.1.2"
-"@parcel/compressor-raw@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.16.3.tgz#2f6c426552398136fdfc5e6abf154a652f49a169"
- integrity sha512-84lI0ULxvjnqDn3yHorMHj2X2g0oQsIwNFYopQWz9UWjnF7g5IU0EFgAAqMCQxKKUV6fttqaQiDDPikXLR6hHA==
- dependencies:
- "@parcel/plugin" "2.16.3"
-
-"@parcel/config-default@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.16.3.tgz#f64d30a6bed04d4a2c8be634a12a9a032ae37cd0"
- integrity sha512-OgB6f+EpCzjeFLoVB5qJzKy0ybB2wPK0hB2aXgD3oYCHWLny7LJOGaktY9OskSn1jfz7Tdit9zLNXOhBTMRujw==
- dependencies:
- "@parcel/bundler-default" "2.16.3"
- "@parcel/compressor-raw" "2.16.3"
- "@parcel/namer-default" "2.16.3"
- "@parcel/optimizer-css" "2.16.3"
- "@parcel/optimizer-html" "2.16.3"
- "@parcel/optimizer-image" "2.16.3"
- "@parcel/optimizer-svg" "2.16.3"
- "@parcel/optimizer-swc" "2.16.3"
- "@parcel/packager-css" "2.16.3"
- "@parcel/packager-html" "2.16.3"
- "@parcel/packager-js" "2.16.3"
- "@parcel/packager-raw" "2.16.3"
- "@parcel/packager-svg" "2.16.3"
- "@parcel/packager-wasm" "2.16.3"
- "@parcel/reporter-dev-server" "2.16.3"
- "@parcel/resolver-default" "2.16.3"
- "@parcel/runtime-browser-hmr" "2.16.3"
- "@parcel/runtime-js" "2.16.3"
- "@parcel/runtime-rsc" "2.16.3"
- "@parcel/runtime-service-worker" "2.16.3"
- "@parcel/transformer-babel" "2.16.3"
- "@parcel/transformer-css" "2.16.3"
- "@parcel/transformer-html" "2.16.3"
- "@parcel/transformer-image" "2.16.3"
- "@parcel/transformer-js" "2.16.3"
- "@parcel/transformer-json" "2.16.3"
- "@parcel/transformer-node" "2.16.3"
- "@parcel/transformer-postcss" "2.16.3"
- "@parcel/transformer-posthtml" "2.16.3"
- "@parcel/transformer-raw" "2.16.3"
- "@parcel/transformer-react-refresh-wrap" "2.16.3"
- "@parcel/transformer-svg" "2.16.3"
-
-"@parcel/core@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.16.3.tgz#fb805957022880cd014f6815e58b315cacd4bd74"
- integrity sha512-b9ll4jaFYfXSv6NZAOJ2P0uuyT/Doel7ho2AHLSUz2thtcL6HEb2+qdV2f9wriVvbEoPAj9VuSOgNc0t0f5iMw==
+"@parcel/compressor-raw@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.16.4.tgz#93ef4db8710ab7bc0efd88f827bca41f6b45d3cc"
+ integrity sha512-IK8IpNhw61B2HKgA1JhGhO9y+ZJFRZNTEmvhN1NdLdPqvgEXm2EunT+m6D9z7xeoeT6XnUKqM0eRckEdD0OXbA==
+ dependencies:
+ "@parcel/plugin" "2.16.4"
+
+"@parcel/config-default@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.16.4.tgz#5e695f26d6d8ef94b33904edc000cbeb257f63e5"
+ integrity sha512-kBxuTY/5trEVnvXk92l7LVkYjNuz3SaqWymFhPjEnc8GY4ZVdcWrWdXWTB9hUhpmRYJctFCyGvM0nN05JTiM2g==
+ dependencies:
+ "@parcel/bundler-default" "2.16.4"
+ "@parcel/compressor-raw" "2.16.4"
+ "@parcel/namer-default" "2.16.4"
+ "@parcel/optimizer-css" "2.16.4"
+ "@parcel/optimizer-html" "2.16.4"
+ "@parcel/optimizer-image" "2.16.4"
+ "@parcel/optimizer-svg" "2.16.4"
+ "@parcel/optimizer-swc" "2.16.4"
+ "@parcel/packager-css" "2.16.4"
+ "@parcel/packager-html" "2.16.4"
+ "@parcel/packager-js" "2.16.4"
+ "@parcel/packager-raw" "2.16.4"
+ "@parcel/packager-svg" "2.16.4"
+ "@parcel/packager-wasm" "2.16.4"
+ "@parcel/reporter-dev-server" "2.16.4"
+ "@parcel/resolver-default" "2.16.4"
+ "@parcel/runtime-browser-hmr" "2.16.4"
+ "@parcel/runtime-js" "2.16.4"
+ "@parcel/runtime-rsc" "2.16.4"
+ "@parcel/runtime-service-worker" "2.16.4"
+ "@parcel/transformer-babel" "2.16.4"
+ "@parcel/transformer-css" "2.16.4"
+ "@parcel/transformer-html" "2.16.4"
+ "@parcel/transformer-image" "2.16.4"
+ "@parcel/transformer-js" "2.16.4"
+ "@parcel/transformer-json" "2.16.4"
+ "@parcel/transformer-node" "2.16.4"
+ "@parcel/transformer-postcss" "2.16.4"
+ "@parcel/transformer-posthtml" "2.16.4"
+ "@parcel/transformer-raw" "2.16.4"
+ "@parcel/transformer-react-refresh-wrap" "2.16.4"
+ "@parcel/transformer-svg" "2.16.4"
+
+"@parcel/core@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.16.4.tgz#a0252f118e3895ae6591f41c4d4c0c6015fbb151"
+ integrity sha512-a0CgrW5A5kwuSu5J1RFRoMQaMs9yagvfH2jJMYVw56+/7NRI4KOtu612SG9Y1ERWfY55ZwzyFxtLWvD6LO+Anw==
dependencies:
"@mischnic/json-sourcemap" "^0.1.1"
- "@parcel/cache" "2.16.3"
- "@parcel/diagnostic" "2.16.3"
- "@parcel/events" "2.16.3"
- "@parcel/feature-flags" "2.16.3"
- "@parcel/fs" "2.16.3"
- "@parcel/graph" "3.6.3"
- "@parcel/logger" "2.16.3"
- "@parcel/package-manager" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/profiler" "2.16.3"
- "@parcel/rust" "2.16.3"
+ "@parcel/cache" "2.16.4"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/events" "2.16.4"
+ "@parcel/feature-flags" "2.16.4"
+ "@parcel/fs" "2.16.4"
+ "@parcel/graph" "3.6.4"
+ "@parcel/logger" "2.16.4"
+ "@parcel/package-manager" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/profiler" "2.16.4"
+ "@parcel/rust" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/types" "2.16.3"
- "@parcel/utils" "2.16.3"
- "@parcel/workers" "2.16.3"
+ "@parcel/types" "2.16.4"
+ "@parcel/utils" "2.16.4"
+ "@parcel/workers" "2.16.4"
base-x "^3.0.11"
browserslist "^4.24.5"
clone "^2.1.2"
@@ -580,361 +587,361 @@
nullthrows "^1.1.1"
semver "^7.7.1"
-"@parcel/diagnostic@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.16.3.tgz#e402872fbf517b381518b2add857b940a3af87db"
- integrity sha512-NBoGGFMqOmbs8i0zGVwTeU0alQ0BkEZe894zAb5jEBQqsRBPmdqogwmARsT4Ix2bN1QBco4o0gn9kBtalFC6IQ==
+"@parcel/diagnostic@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.16.4.tgz#f9169eb08b42c806a69172d3d233a01b801994f1"
+ integrity sha512-YN5CfX7lFd6yRLxyZT4Sj3sR6t7nnve4TdXSIqapXzQwL7Bw+sj79D95wTq2rCm3mzk5SofGxFAXul2/nG6gcQ==
dependencies:
"@mischnic/json-sourcemap" "^0.1.1"
nullthrows "^1.1.1"
-"@parcel/error-overlay@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/error-overlay/-/error-overlay-2.16.3.tgz#89e726c7a955b37441b00e0ff8bca3244dfd7c17"
- integrity sha512-JqJR4Fl5SwTmqDEuCAC8F1LmNLWpjfiJ+hGp3CoLb0/9EElRxlpkuP/SxTe2/hyXevpfn3bfvS1cn/mWhHUc3w==
-
-"@parcel/events@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.16.3.tgz#69d6e54410b8de0d28c00f31c6527af4dab82db8"
- integrity sha512-rAh/yXwtHYcKWmi9Tjjf5t95UdBVhhlyJkIYN25/PYKdSRBcQ9c1rd8/fvOeZKy1/fSiOcEXqm6dK7bhLSCaww==
-
-"@parcel/feature-flags@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/feature-flags/-/feature-flags-2.16.3.tgz#b74f66fcd7b3e63b020bd6b534e77376a150c668"
- integrity sha512-D15/cM/mAO8yv0NQ9kFBxXZ7C3A+jAq+9tVfrjYegofMk18pQoXJz6X/po2Kq1PzO7pjydn7PqYMB/O9p/+zbQ==
-
-"@parcel/fs@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.16.3.tgz#28e618009015eea7fd942da0f16e2ac6caf58ba1"
- integrity sha512-InMXHVIfDUSimjBoGJcdNlNjoIsDQ8MUDN8UJG4jnjJQ6DDor+W+yg4sw/40tToUqIyi99lVhQlpkBA+nHLpOQ==
- dependencies:
- "@parcel/feature-flags" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/types-internal" "2.16.3"
- "@parcel/utils" "2.16.3"
+"@parcel/error-overlay@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/error-overlay/-/error-overlay-2.16.4.tgz#8edc66f8ff7c2d6c57f9ae0ee2cf49e48ba03756"
+ integrity sha512-e8KYKnMsfmQnqIhsUWBUZAXlDK30wkxsAGle1tZ0gOdoplaIdVq/WjGPatHLf6igLM76c3tRn2vw8jZFput0jw==
+
+"@parcel/events@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.16.4.tgz#657f5b0ef305bb533e8c5df3538b4cef36bef0fd"
+ integrity sha512-slWQkBRAA7o0cN0BLEd+yCckPmlVRVhBZn5Pn6ktm4EzEtrqoMzMeJOxxH8TXaRzrQDYnTcnYIHFgXWd4kkUfg==
+
+"@parcel/feature-flags@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/feature-flags/-/feature-flags-2.16.4.tgz#daa88354e7d024b995e750e38bd319717cd70a69"
+ integrity sha512-nYdx53siKPLYikHHxfzgjzzgxdrjquK6DMnuSgOTyIdRG4VHdEN0+NqKijRLuVgiUFo/dtxc2h+amwqFENMw8w==
+
+"@parcel/fs@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.16.4.tgz#771c4494acd3052c421891e3da755ee3d9109f43"
+ integrity sha512-maCMOiVn7oJYZlqlfxgLne8n6tSktIT1k0AeyBp4UGWCXyeJUJ+nL7QYShFpKNLtMLeF0cEtgwRAknWzbcDS1g==
+ dependencies:
+ "@parcel/feature-flags" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/types-internal" "2.16.4"
+ "@parcel/utils" "2.16.4"
"@parcel/watcher" "^2.0.7"
- "@parcel/workers" "2.16.3"
+ "@parcel/workers" "2.16.4"
-"@parcel/graph@3.6.3":
- version "3.6.3"
- resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-3.6.3.tgz#122a892d32fec190a08a251d2a856fbdb8f6a776"
- integrity sha512-3qV99HCHrPR1CnMOHkwwpmPBimVMd3d/GcEcgOHUKi+2mS0KZ4TwMs/THaIWtJx7q5jrhqEht+IyQ1Smupo49g==
+"@parcel/graph@3.6.4":
+ version "3.6.4"
+ resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-3.6.4.tgz#7f76142f8dae19c4753c3962d9668c3b3769fb3e"
+ integrity sha512-Cj9yV+/k88kFhE+D+gz0YuNRpvNOCVDskO9pFqkcQhGbsGq6kg2XpZ9V7HlYraih31xf8Vb589bZOwjKIiHixQ==
dependencies:
- "@parcel/feature-flags" "2.16.3"
+ "@parcel/feature-flags" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/logger@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.16.3.tgz#074d18e8714d4d7445f00cd949a6d7b905e9f84f"
- integrity sha512-dHUJk8dvo2wOg3dIqSjNGqlVqsRn4hTZVbgTShaImaLTWdueaKfMojxo79P7T3em49y0dQb0m+xl2SunDhtwsA==
+"@parcel/logger@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.16.4.tgz#c21d695030f62c3c5be90a811942aff402ff99c3"
+ integrity sha512-QR8QLlKo7xAy9JBpPDAh0RvluaixqPCeyY7Fvo2K7hrU3r85vBNNi06pHiPbWoDmB4x1+QoFwMaGnJOHR+/fMA==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/events" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/events" "2.16.4"
-"@parcel/markdown-ansi@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.16.3.tgz#96db3630b3f2fcad50d8a943217e2c33c51b2454"
- integrity sha512-r0QQpS44jNueY8lcZcSoUua3kJfI5kDZrJvFgi1jrkyxwDUfq3L0xWQjxHrXzv8K6uFAeU+teoq8JcWLVLXa1w==
+"@parcel/markdown-ansi@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.16.4.tgz#8d11a49327eb38880d4b46ecb560e547ff93f57b"
+ integrity sha512-0+oQApAVF3wMcQ6d1ZfZ0JsRzaMUYj9e4U+naj6YEsFsFGOPp+pQYKXBf1bobQeeB7cPKPT3SUHxFqced722Hw==
dependencies:
chalk "^4.1.2"
-"@parcel/namer-default@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.16.3.tgz#e67ea39e3e1dc19a3b65694721147db0323f44e1"
- integrity sha512-4MwRm8ZnloMdQ6sAMrTDxMiPVN1fV+UcBIrA0Fpp4kD3XLkqSAUCLnjl13+VrPelfh01irM6QnpK4JTKBqRk0A==
+"@parcel/namer-default@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.16.4.tgz#3b2d3c80f41071a199d136bb26953fb377517432"
+ integrity sha512-CE+0lFg881sJq575EXxj2lKUn81tsS5itpNUUErHxit195m3PExyAhoXM6ed/SXxwi+uv+T5FS/jjDLBNuUFDA==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/node-resolver-core@3.7.3":
- version "3.7.3"
- resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-3.7.3.tgz#6ec9c4ad0a0733fc1e3f4acbabb0e065250fa763"
- integrity sha512-0xdXyhGcGwtYmfWwEwzdVVGnTaADdTScx1S8IXiK0Nh3S1b4ilGqnKzw8fVsJCsBMvQA5e251EDFeG3qTnUsnw==
+"@parcel/node-resolver-core@3.7.4":
+ version "3.7.4"
+ resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-3.7.4.tgz#d7eafcb42b1118621a5d33216c3d77f36ec8ed5d"
+ integrity sha512-b3VDG+um6IWW5CTod6M9hQsTX5mdIelKmam7mzxzgqg4j5hnycgTWqPMc9UxhYoUY/Q/PHfWepccNcKtvP5JiA==
dependencies:
"@mischnic/json-sourcemap" "^0.1.1"
- "@parcel/diagnostic" "2.16.3"
- "@parcel/fs" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/fs" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
nullthrows "^1.1.1"
semver "^7.7.1"
-"@parcel/optimizer-css@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.16.3.tgz#ad6c9d34610b4817de8342c278f629068cafc433"
- integrity sha512-j/o9bGtu1Fe7gJYQD+/SeJ5yR7FmS6Z7e6CtTkVxjeeq0/IdR0KoZOCkJ4cRETPnm+wkyQVlY8koAAFbEEqV8w==
+"@parcel/optimizer-css@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.16.4.tgz#269584b0d739781ed5218316541cbc7a1484d2bc"
+ integrity sha512-aqdXCtmvpcXYgJFGk2DtXF34wuM2TD1fZorKMrJdKB9sSkWVRs1tq6RAXQrbi0ZPDH9wfE/9An3YdkTex7RHuQ==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
+ "@parcel/utils" "2.16.4"
browserslist "^4.24.5"
lightningcss "^1.30.1"
nullthrows "^1.1.1"
-"@parcel/optimizer-html@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/optimizer-html/-/optimizer-html-2.16.3.tgz#04ca8a9e48412920fd6340312b57a2c2a073968e"
- integrity sha512-EBmjY+QRa/in05wRWiL6B/kQ1ERemdg4W9py+V2w0tJx1n6yOvtjPGvivYtU+s82rlVlx6DN3DFU13iGRt0FuQ==
- dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
-
-"@parcel/optimizer-image@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.16.3.tgz#9b43f33ed8db0c6da254dec27546026b38248785"
- integrity sha512-PbGsDXbbWyOnkpWn3jgZxtAp8l8LNXl7DCv5Q4l1TR6k4sULjmxTTPY6+AkY6H84cAN7s5h6F8k2XeN3ygXWCA==
- dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
- "@parcel/workers" "2.16.3"
-
-"@parcel/optimizer-svg@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/optimizer-svg/-/optimizer-svg-2.16.3.tgz#0ef8bdfc4466128b4d40927ed6069df05f668181"
- integrity sha512-fgQhrqu5pKtEaM9G//PvBZSuCDP6ZVbGyFnePKCzqnXJ173/Y+4kUbNOrPi7wE4HupWMsJRNUf/vyCu+lXdOiQ==
- dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
-
-"@parcel/optimizer-swc@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/optimizer-swc/-/optimizer-swc-2.16.3.tgz#50241771fea269cbcaa4b62bfbc900ab3f91856b"
- integrity sha512-8P5Bis2SynQ6sPW1bwB6H8WK+nFF61RCKzlGnTPoh1YE36dubYqUreYYISMLFt/rG8eb+Ja78DQLPZTVP3sfQQ==
- dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
+"@parcel/optimizer-html@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/optimizer-html/-/optimizer-html-2.16.4.tgz#85d8975288c499419a47341975e7aa42c5fb7bf3"
+ integrity sha512-vg/R2uuSni+NYYUUV8m+5bz8p5zBv8wc/nNleoBnGuCDwn7uaUwTZ8Gt9CjZO8jjG0xCLILoc/TW+e2FF3pfgQ==
+ dependencies:
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
+
+"@parcel/optimizer-image@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.16.4.tgz#878a3d29af2fde7f9e37dd6f496a3bdacb498dc0"
+ integrity sha512-2RV54WnvMYr18lxSx7Zlx/DXpJwMzOiPxDnoFyvaUoYutvgHO6chtcgFgh1Bvw/PoI95vYzlTkZ8QfUOk5A0JA==
+ dependencies:
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
+ "@parcel/workers" "2.16.4"
+
+"@parcel/optimizer-svg@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/optimizer-svg/-/optimizer-svg-2.16.4.tgz#f2131c60a4144e7bcfe5f8ac1e100e32a0d54a88"
+ integrity sha512-22+BqIffCrVErg8y2XwhasbTaFNn75OKXZ3KTDBIfOSAZKLUKs1iHfDXETzTRN7cVcS+Q36/6EHd7N/RA8i1fg==
+ dependencies:
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
+
+"@parcel/optimizer-swc@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/optimizer-swc/-/optimizer-swc-2.16.4.tgz#29b5b6a7c2245dc8fe24da0136d34a56af09d99c"
+ integrity sha512-+URqwnB6u1gqaLbG1O1DDApH+UVj4WCbK9No1fdxLBxQ9a84jyli25o1kK1hYB9Nb/JMyYNnEBfvYUW6RphOxw==
+ dependencies:
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
+ "@parcel/utils" "2.16.4"
"@swc/core" "^1.11.24"
nullthrows "^1.1.1"
-"@parcel/package-manager@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.16.3.tgz#00acb13ef7bd47ff14e1aa3914dd638835ed4eb5"
- integrity sha512-TySTY93SyGfu8E5YWiekumw6sm/2+LBHcpv1JWWAfNd+1b/x3WB5QcRyEk6mpnOo7ChQOfqykzUaBcrmLBGaSw==
- dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/fs" "2.16.3"
- "@parcel/logger" "2.16.3"
- "@parcel/node-resolver-core" "3.7.3"
- "@parcel/types" "2.16.3"
- "@parcel/utils" "2.16.3"
- "@parcel/workers" "2.16.3"
+"@parcel/package-manager@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.16.4.tgz#186df5779bae20aa563d1c4778ba3a17310d7e58"
+ integrity sha512-obWv9gZgdnkT3Kd+fBkKjhdNEY7zfOP5gVaox5i4nQstVCaVnDlMv5FwLEXwehL+WbwEcGyEGGxOHHkAFKk7Cg==
+ dependencies:
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/fs" "2.16.4"
+ "@parcel/logger" "2.16.4"
+ "@parcel/node-resolver-core" "3.7.4"
+ "@parcel/types" "2.16.4"
+ "@parcel/utils" "2.16.4"
+ "@parcel/workers" "2.16.4"
"@swc/core" "^1.11.24"
semver "^7.7.1"
-"@parcel/packager-css@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.16.3.tgz#b30411bedf8e7351f3d3d5a7046a30a405767153"
- integrity sha512-CUwMRif1ZGBfociDt6m18L7sgafsquo0+NYRDXCTHmig3w7zm5saE4PXborfzRI/Lj3kBUkJYH//NQGITHv1Yg==
+"@parcel/packager-css@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.16.4.tgz#cc6ed5c466dd45a2d3a7b9b2163d5886d2d22b00"
+ integrity sha512-rWRtfiX+VVIOZvq64jpeNUKkvWAbnokfHQsk/js1s5jD4ViNQgPcNLiRaiIANjymqL6+dQqWvGUSW2a5FAZYfg==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
+ "@parcel/utils" "2.16.4"
lightningcss "^1.30.1"
nullthrows "^1.1.1"
-"@parcel/packager-html@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.16.3.tgz#349610c6fd5c586553ddbfda4f854c33c518293b"
- integrity sha512-hluJXpvcW2EwmBxO/SalBiX5SIYJ7jGTkhFq5ka2wrQewFxaAOv2BVTuFjl1AAnWzjigcNhC4n0jkQUckCNW4g==
+"@parcel/packager-html@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.16.4.tgz#6e785cc4b424503fe13389cecad517c85383c8f6"
+ integrity sha512-AWo5f6SSqBsg2uWOsX0gPX8hCx2iE6GYLg2Z4/cDy2mPlwDICN8/bxItEztSZFmObi+ti26eetBKRDxAUivyIQ==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/types" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/types" "2.16.4"
+ "@parcel/utils" "2.16.4"
-"@parcel/packager-js@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.16.3.tgz#384c7cf52066f87844ee922d6ff5659f424aac3e"
- integrity sha512-01fufzVOs9reEDq9OTUyu5Kpasd8nGvBJEUytagM6rvNlEpmlUX5HvoAzUMSTyYeFSH+1VnX6HzK6EcQNY9Y8Q==
+"@parcel/packager-js@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.16.4.tgz#ee1d37ed4322a38b34627015f88510204fef071b"
+ integrity sha512-L2o39f/fhta+hxto7w8OTUKdstY+te5BmHZREckbQm0KTBg93BG7jB0bfoxLSZF0d8uuAYIVXjzeHNqha+du1g==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/types" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/types" "2.16.4"
+ "@parcel/utils" "2.16.4"
globals "^13.24.0"
nullthrows "^1.1.1"
-"@parcel/packager-raw@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.16.3.tgz#f8afd492942c60d6a250f620999ecdb66bb63bdf"
- integrity sha512-GCehb36D2xe8P8gftyZcjNr3XcUzBgRzWcasM4I0oPaLRZw4nuIu60cwTsGk6/HhUYDq8uPze+gr1L4pApRrjw==
+"@parcel/packager-raw@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.16.4.tgz#6390274cc7784e037ccb5ad226777beb588d141e"
+ integrity sha512-A9j60G9OmbTkEeE4WRMXCiErEprHLs9NkUlC4HXCxmSrPMOVaMaMva2LdejE3A9kujZqYtYfuc8+a+jN+Nro4w==
dependencies:
- "@parcel/plugin" "2.16.3"
+ "@parcel/plugin" "2.16.4"
-"@parcel/packager-svg@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.16.3.tgz#8974add3addbf0d328722d4638e2cadc3800d7ac"
- integrity sha512-1TLmU8zcRBySOD3WXGUhTjmIurJoOMwQ3aIiyHXn4zjrl4+VPw/WnUoVGpMwUW1T7rb2/22BKPGAAxbOLDqxLQ==
+"@parcel/packager-svg@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.16.4.tgz#61736d3bd6c43507b9daaa6dcb9501edb6108892"
+ integrity sha512-LT9l7eInFrAZJ6w3mYzAUgDq3SIzYbbQyW46Dz26M9lJQbf6uCaATUTac3BEHegW0ikDuw4OOGHK41BVqeeusg==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/types" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/types" "2.16.4"
+ "@parcel/utils" "2.16.4"
-"@parcel/packager-wasm@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/packager-wasm/-/packager-wasm-2.16.3.tgz#ef5fdff348659a59d26bee936786b15db39be430"
- integrity sha512-RfRM/RaA4eWV+qUt7A9Vo2VlvZx50Rfs81kZ4WBhxzey2BGAvBSJWceYEUnI7JuDmrHjDMDe6y0+gLNmELeL1g==
+"@parcel/packager-wasm@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/packager-wasm/-/packager-wasm-2.16.4.tgz#2869d1df61c0247d22b43769024310784a5f5f05"
+ integrity sha512-AY96Aqu/RpmaSZK2RGkIrZWjAperDw8DAlxLAiaP1D/RPVnikZtl5BmcUt/Wz3PrzG7/q9ZVqqKkWsLmhkjXZQ==
dependencies:
- "@parcel/plugin" "2.16.3"
+ "@parcel/plugin" "2.16.4"
-"@parcel/plugin@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.16.3.tgz#844bfe6f841ab200c52f46ef6e970e2cdf1122bd"
- integrity sha512-w4adN/E2MBbNzUwuGWcUkilrf7B6eQThPRdgiw2awIY0/t0C1gN/hhBfUeWt7vt0WcvWlXcyR/OGzU/r0nPteA==
+"@parcel/plugin@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.16.4.tgz#a7fa42863fc85215cb4ede5ef1b709075dd42317"
+ integrity sha512-aN2VQoRGC1eB41ZCDbPR/Sp0yKOxe31oemzPx1nJzOuebK2Q6FxSrJ9Bjj9j/YCaLzDtPwelsuLOazzVpXJ6qg==
dependencies:
- "@parcel/types" "2.16.3"
+ "@parcel/types" "2.16.4"
-"@parcel/profiler@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/profiler/-/profiler-2.16.3.tgz#a154c0bb4b29c559381e6a21b10f31cf81863682"
- integrity sha512-/4cVsLfv36fdphm+JiReeXXT3RD6258L79C2kjpD06i84sxyNPQVbFldgWRppbHW2KBR/D6XhIzHcwoDUYtTbw==
+"@parcel/profiler@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/profiler/-/profiler-2.16.4.tgz#f5e732fa5be2a634a37e35b189652d6d67bd5a11"
+ integrity sha512-R3JhfcnoReTv2sVFHPR2xKZvs3d3IRrBl9sWmAftbIJFwT4rU70/W7IdwfaJVkD/6PzHq9mcgOh1WKL4KAxPdA==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/events" "2.16.3"
- "@parcel/types-internal" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/events" "2.16.4"
+ "@parcel/types-internal" "2.16.4"
chrome-trace-event "^1.0.2"
-"@parcel/reporter-cli@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.16.3.tgz#bb95adaeae85d4d54f5d9d06703fa556a5872ca4"
- integrity sha512-kIwhJy97xlgvNsUhn3efp6PxUfWCiiPG9ciDnAGBXpFmKWl63WQR6QIXNuNgrQremUTzIHJ02h6/+LyBJD4wjw==
+"@parcel/reporter-cli@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.16.4.tgz#0da65678405755cef281f36ac4ddb6b62248804c"
+ integrity sha512-DQx9TwcTZrDv828+tcwEi//xyW7OHTGzGX1+UEVxPp0mSzuOmDn0zfER8qNIqGr1i4D/FXhb5UJQDhGHV8mOpQ==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/types" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/types" "2.16.4"
+ "@parcel/utils" "2.16.4"
chalk "^4.1.2"
term-size "^2.2.1"
-"@parcel/reporter-dev-server@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.16.3.tgz#45022541c20adcd524dd6875141492f4eee452b8"
- integrity sha512-c2YEHU3ePOSUO+JXoehn3r0ruUlP2i4xvHfwHLHI3NW/Ymlp4Gy9rWyyYve/zStfoEOyMN/vKRWKtxr6nCy9DQ==
+"@parcel/reporter-dev-server@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.16.4.tgz#ec32a91e20beb5daa5a5e8f137247563ad70baef"
+ integrity sha512-YWvay25htQDifpDRJ0+yFh6xUxKnbfeJxYkPYyuXdxpEUhq4T0UWW0PbPCN/wFX7StgeUTXq5Poeo/+eys9m3w==
dependencies:
- "@parcel/codeframe" "2.16.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/codeframe" "2.16.4"
+ "@parcel/plugin" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
+ "@parcel/utils" "2.16.4"
-"@parcel/reporter-tracer@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/reporter-tracer/-/reporter-tracer-2.16.3.tgz#e97c5fd83cd6b1113483634e77e8dc7edea14ba6"
- integrity sha512-DqQQRQC6JKQcYo8fAC69JGri++WC9cTRZFH2QJdbcMXnmeCW0YjBwHsl65C0Q/8aO6lwVlV0P1waMPW3iQw+uA==
+"@parcel/reporter-tracer@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/reporter-tracer/-/reporter-tracer-2.16.4.tgz#34e44123e444e6aa64cdc81d59bf333802deb74c"
+ integrity sha512-JKnlXpPepak0/ZybmZn9JtyjJiDBWYrt7ZUlXQhQb0xzNcd/k+RqfwVkTKIwyFHsWtym0cwibkvsi2bWFzS7tw==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
chrome-trace-event "^1.0.3"
nullthrows "^1.1.1"
-"@parcel/resolver-default@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.16.3.tgz#cbdf25cc229734780251baab6b19b329224923a8"
- integrity sha512-2bf2VRKt1fZRZbi85SBLrePr4Eid0zXUQMy+MRcFoVZ8MaxsjvWjnlxHW71cWNcRQATUOX/0w0z0Gcf7Kjrh2g==
+"@parcel/resolver-default@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.16.4.tgz#d7b90177e2bee662cca57edb5c0eb82e8034ea2f"
+ integrity sha512-wJe9XQS0hn/t32pntQpJbls3ZL8mGVVhK9L7s7BTmZT9ufnvP2nif1psJz/nbgnP9LF6mLSk43OdMJKpoStsjQ==
dependencies:
- "@parcel/node-resolver-core" "3.7.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/node-resolver-core" "3.7.4"
+ "@parcel/plugin" "2.16.4"
-"@parcel/runtime-browser-hmr@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.16.3.tgz#db9474c253a3ecee48d611470547260320686479"
- integrity sha512-dN5Kv6/BLaKAf80zogimvSPZYQRA+h+o3rKQLnxid2FilVRTCjz+FOcuMsT/EqAJXai1mKjrxtqlM9IJ4oSV1A==
+"@parcel/runtime-browser-hmr@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.16.4.tgz#519b86a6fde8c3f5ef3ef5b714fa208a029f7059"
+ integrity sha512-asx7p3NjUSfibI3bC7+8+jUIGHWVk2Zuq9SjJGCGDt+auT9A4uSGljnsk1BWWPqqZ0WILubq4czSAqm0+wt4cw==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
-"@parcel/runtime-js@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.16.3.tgz#d63b83214af5e36099863a3bf8dc06ed1c235097"
- integrity sha512-Xk1G7A0g5Dbm374V8piDbxLRQoQ1JiKIChXzQuiQ755A22JYOSP0yA2djBEuB7KWPwFKDd4f9DFTVDn6VclPaQ==
+"@parcel/runtime-js@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.16.4.tgz#ea7c7f1c8b0997c6a6b33561b65d8e7ed305d65c"
+ integrity sha512-gUKmsjg+PULQBu2QbX0QKll9tXSqHPO8NrfxHwWb2lz5xDKDos1oV0I7BoMWbHhUHkoToXZrm654oGViujtVUA==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/runtime-rsc@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/runtime-rsc/-/runtime-rsc-2.16.3.tgz#1cc804e83473b3fecb0e528571283ae53925a0ec"
- integrity sha512-QR+4BjGE2OqLcjh6WfAMrNoM0FubxvJNH9p31yjI4H1ivrvTJECanvVZ6C7QRR/30l+WAYb5USrcYJVMwHi1zg==
+"@parcel/runtime-rsc@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/runtime-rsc/-/runtime-rsc-2.16.4.tgz#e57c229bfcc3464772dc5ea893118a3a5edb41cf"
+ integrity sha512-CHkotYE/cNiUjJmrc5FD9YhlFp1UF5wMNNJmoWaL40eBzsqcaV0sSn5V3bNapwewn3wrMYgdPgvOTHfaZaG73A==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/runtime-service-worker@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.16.3.tgz#70dc723e2549bcf7985b6325fa1c19f419979e49"
- integrity sha512-O+jhRFNThRAxsHOW6RYcYR6+sA9MxeGTmbVRguFyM12OqzuXRTuuv9x2RDSGP/cgBBCpVuq5JvK8KwS2RB26Gg==
+"@parcel/runtime-service-worker@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.16.4.tgz#f0200cb88f0b77d2ecbdf14b9b27a43572811010"
+ integrity sha512-FT0Q58bf5Re+dq5cL2XHbxqHHFZco6qtRijeVpT3TSPMRPlniMArypSytTeZzVNL7h/hxjWsNu7fRuC0yLB5hA==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/rust-darwin-arm64@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-darwin-arm64/-/rust-darwin-arm64-2.16.3.tgz#2531454733a705aaf55099f08cc308f416277dd0"
- integrity sha512-9JG19DDNjIpvlI1b8VYIjvCaulftd6/J09/Rj2A8KgREv6EtCDkus8jCsNw7Jacj2HIWg23kxJY3XKcJ9pkiug==
-
-"@parcel/rust-darwin-x64@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-darwin-x64/-/rust-darwin-x64-2.16.3.tgz#9bff6f0f7070a7405fc2cc0d3740df60eda7fbd1"
- integrity sha512-9mG6M6SGYiCO9IfD85Bixg5udXoy2IQHCRdBoQmpNej5+FrDW1a3FeDwDzqOFtl9b7axpzPEVb7zp+WK36Rn4w==
-
-"@parcel/rust-linux-arm-gnueabihf@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-linux-arm-gnueabihf/-/rust-linux-arm-gnueabihf-2.16.3.tgz#951f2ab7e55af545ed08aadc62968ddeeee90ddd"
- integrity sha512-zSA1Dz5JWS28DkEMjEQNmf8qk55dR6rcKtwrw5CMg3Ndt30ugrGtRechsqEpXSYYxcDY1kmZ779LwiTUdkdCrQ==
-
-"@parcel/rust-linux-arm64-gnu@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-linux-arm64-gnu/-/rust-linux-arm64-gnu-2.16.3.tgz#37588b03300600e4af191631b622762b4a29dcac"
- integrity sha512-PvjO0U6qM0JjRCH2eKi3JNKgBVWDBP3VrMEUXJJM8K37ylfLTozK0f7oK2M03voCS1WjKrduRGjJNk8EZrBPow==
-
-"@parcel/rust-linux-arm64-musl@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-linux-arm64-musl/-/rust-linux-arm64-musl-2.16.3.tgz#d724b65ee432ffec21e8e712b4cec4b43ec6055f"
- integrity sha512-a4TZB9/Y/y8DQ55XZXh9bNb5yIC9CAoK2YK8g3OytauC8OrHGtIIVlF+E1UCn/FPBFr2dobYOeih/InvLKITpQ==
-
-"@parcel/rust-linux-x64-gnu@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-linux-x64-gnu/-/rust-linux-x64-gnu-2.16.3.tgz#bca956ad2ec11eb06a55516dad2c954df9de8bfb"
- integrity sha512-6/a/5jDcVwE0xpLSLGI9T2pclgnad0jVFRH/4Gm9yQ5fl2gpYghjg3fcCNeSjJ/aBNFKlOeKLlp/oBSlTtlkoQ==
-
-"@parcel/rust-linux-x64-musl@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-linux-x64-musl/-/rust-linux-x64-musl-2.16.3.tgz#faea88a0c31febcd6dad59e9cc7000edc1ac77b9"
- integrity sha512-gTUlFvJBLR3UxNjGs076wVuFZyx+X6G6opJzBFaSG9XqLhLo+VrpqHpjCx+SCwSufDLTVq8rWJbwpvbe2EhRJg==
-
-"@parcel/rust-win32-x64-msvc@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust-win32-x64-msvc/-/rust-win32-x64-msvc-2.16.3.tgz#25e37325fc6333e7ca58d4585385dd88911b07ce"
- integrity sha512-/kyr5CL4XFJpMj9CvW8K1NNNqkzyOhxc7ibXhykiPyPiGOwO/ZbqnfDhqVx3JMSjOASeW1e6UlGNjnfTPvFkGQ==
-
-"@parcel/rust@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/rust/-/rust-2.16.3.tgz#74136baf6507e9f924b00a145637cfaf31636753"
- integrity sha512-pUsgURnDdlHA9AqvEcm124/9+DB7GM7Mk0qQ9XDNiznl09n8XZ67lf/IIvaMW7y0vQ7FpTzRIrRzAJhGyMRbMw==
+"@parcel/rust-darwin-arm64@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-darwin-arm64/-/rust-darwin-arm64-2.16.4.tgz#13f0a1327c9e02ae27de18db6143b47177e29264"
+ integrity sha512-P3Se36H9EO1fOlwXqQNQ+RsVKTGn5ztRSUGbLcT8ba6oOMmU1w7J4R810GgsCbwCuF10TJNUMkuD3Q2Sz15Q3Q==
+
+"@parcel/rust-darwin-x64@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-darwin-x64/-/rust-darwin-x64-2.16.4.tgz#e3b5df8b438dbc865110a38546ef0b5cacb89785"
+ integrity sha512-8aNKNyPIx3EthYpmVJevIdHmFsOApXAEYGi3HU69jTxLgSIfyEHDdGE9lEsMvhSrd/SSo4/euAtiV+pqK04wnA==
+
+"@parcel/rust-linux-arm-gnueabihf@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-linux-arm-gnueabihf/-/rust-linux-arm-gnueabihf-2.16.4.tgz#d315b4c88332739325bf1841662f4b7e6344e872"
+ integrity sha512-QrvqiSHaWRLc0JBHgUHVvDthfWSkA6AFN+ikV1UGENv4j2r/QgvuwJiG0VHrsL6pH5dRqj0vvngHzEgguke9DA==
+
+"@parcel/rust-linux-arm64-gnu@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-linux-arm64-gnu/-/rust-linux-arm64-gnu-2.16.4.tgz#64d23137e1578d559a615f944149cf35815e956e"
+ integrity sha512-f3gBWQHLHRUajNZi3SMmDQiEx54RoRbXtZYQNuBQy7+NolfFcgb1ik3QhkT7xovuTF/LBmaqP3UFy0PxvR/iwQ==
+
+"@parcel/rust-linux-arm64-musl@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-linux-arm64-musl/-/rust-linux-arm64-musl-2.16.4.tgz#c3396df8434da0e32cc58e18063ce31f5fd80f79"
+ integrity sha512-cwml18RNKsBwHyZnrZg4jpecXkWjaY/mCArocWUxkFXjjB97L56QWQM9W86f2/Y3HcFcnIGJwx1SDDKJrV6OIA==
+
+"@parcel/rust-linux-x64-gnu@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-linux-x64-gnu/-/rust-linux-x64-gnu-2.16.4.tgz#546ca77267717077a4e92364b9d688731a657193"
+ integrity sha512-0xIjQaN8hiG0F9R8coPYidHslDIrbfOS/qFy5GJNbGA3S49h61wZRBMQqa7JFW4+2T8R0J9j0SKHhLXpbLXrIg==
+
+"@parcel/rust-linux-x64-musl@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-linux-x64-musl/-/rust-linux-x64-musl-2.16.4.tgz#d1db7d43b0527c5dbc707e2576760e5161204937"
+ integrity sha512-fYn21GIecHK9RoZPKwT9NOwxwl3Gy3RYPR6zvsUi0+hpFo19Ph9EzFXN3lT8Pi5KiwQMCU4rsLb5HoWOBM1FeA==
+
+"@parcel/rust-win32-x64-msvc@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust-win32-x64-msvc/-/rust-win32-x64-msvc-2.16.4.tgz#998c2252341a6b0a2006e4bc056f4f27f9a8107f"
+ integrity sha512-TcpWC3I1mJpfP2++018lgvM7UX0P8IrzNxceBTHUKEIDMwmAYrUKAQFiaU0j1Ldqk6yP8SPZD3cvphumsYpJOQ==
+
+"@parcel/rust@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/rust/-/rust-2.16.4.tgz#a5b3098bd740555f39487050ac5bd4ee6a846d27"
+ integrity sha512-RBMKt9rCdv6jr4vXG6LmHtxzO5TuhQvXo1kSoSIF7fURRZ81D1jzBtLxwLmfxCPsofJNqWwdhy5vIvisX+TLlQ==
optionalDependencies:
- "@parcel/rust-darwin-arm64" "2.16.3"
- "@parcel/rust-darwin-x64" "2.16.3"
- "@parcel/rust-linux-arm-gnueabihf" "2.16.3"
- "@parcel/rust-linux-arm64-gnu" "2.16.3"
- "@parcel/rust-linux-arm64-musl" "2.16.3"
- "@parcel/rust-linux-x64-gnu" "2.16.3"
- "@parcel/rust-linux-x64-musl" "2.16.3"
- "@parcel/rust-win32-x64-msvc" "2.16.3"
+ "@parcel/rust-darwin-arm64" "2.16.4"
+ "@parcel/rust-darwin-x64" "2.16.4"
+ "@parcel/rust-linux-arm-gnueabihf" "2.16.4"
+ "@parcel/rust-linux-arm64-gnu" "2.16.4"
+ "@parcel/rust-linux-arm64-musl" "2.16.4"
+ "@parcel/rust-linux-x64-gnu" "2.16.4"
+ "@parcel/rust-linux-x64-musl" "2.16.4"
+ "@parcel/rust-win32-x64-msvc" "2.16.4"
"@parcel/source-map@^2.1.1":
version "2.1.1"
@@ -943,167 +950,167 @@
dependencies:
detect-libc "^1.0.3"
-"@parcel/transformer-babel@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.16.3.tgz#623f1261c654b5177a4d6b9c8b13feaf33b70986"
- integrity sha512-Jsusa2xWlgrmBYmvuC70/SIvcNdYZj3NyQhCxTOARV2scksSKH8iSvNsMKepYiZl6nHRNOmnGOShz9xJqNpUDw==
+"@parcel/transformer-babel@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.16.4.tgz#223c808aefe8246b922c69f1d441bbe4b9c0439e"
+ integrity sha512-CMDUOQYX7+cmeyHxHSFnoPcwvXNL7rRFE+Q06uVFzsYYiVhbwGF/1J5Bx4cW3Froumqla4YTytTsEteJEybkdA==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
+ "@parcel/utils" "2.16.4"
browserslist "^4.24.5"
json5 "^2.2.3"
nullthrows "^1.1.1"
semver "^7.7.1"
-"@parcel/transformer-css@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.16.3.tgz#dd4f7b5c5835a8283fcae3faa694fd9d09be0e4d"
- integrity sha512-RKGfjvQQVYpd27Ag7QHzBEjqfN/hj6Yf6IlbUdOp06bo+XOXQXe5/n2ulJ1EL9ZjyDOtXbB94A7QzSQmtFGEow==
+"@parcel/transformer-css@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.16.4.tgz#d3f76a5fae8691eaa635d87465d867dd2bd90043"
+ integrity sha512-VG/+DbDci2HKe20GFRDs65ZQf5GUFfnmZAa1BhVl/MO+ijT3XC3eoVUy5cExRkq4VLcPY4ytL0g/1T2D6x7lBQ==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
+ "@parcel/utils" "2.16.4"
browserslist "^4.24.5"
lightningcss "^1.30.1"
nullthrows "^1.1.1"
-"@parcel/transformer-html@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.16.3.tgz#d8609fdcd6e8090356ef6e4a9e8f33948007b52b"
- integrity sha512-j/f+fR3hS9g3Kw4mySyF2sN4mp0t6amq3x52SAptpa4C7w8XVWproc+3ZLgjzi91OPqNeQAQUNQMy86AfuMuEw==
+"@parcel/transformer-html@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.16.4.tgz#bae5a32f42587fc6fc7114c61d4f0d7523545e04"
+ integrity sha512-w6JErYTeNS+KAzUAER18NHFIFFvxiLGd4Fht1UYcb/FDjJdLAMB/FljyEs0Rto/WAhZ2D0MuSL25HQh837R62g==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
-"@parcel/transformer-image@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.16.3.tgz#af0b2177e500d9e01e400af3e9ddb46a42bfdb23"
- integrity sha512-q8BhaGSaGtIP1JPxDpRoRxs5Oa17sVR4c0kyPyxwP0QoihKth1eQElbINx+7Ikbt7LoGucPUKEsnxrDzkUt8og==
+"@parcel/transformer-image@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.16.4.tgz#1f7b6dc37acdec4d2c1eed106bb846263d9ce3d8"
+ integrity sha512-ZzIn3KvvRqMfcect4Dy+57C9XoQXZhpVJKBdQWMp9wM1qJEgsVgGDcaSBYCs/UYSKMRMP6Wm20pKCt408RkQzg==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
- "@parcel/workers" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
+ "@parcel/workers" "2.16.4"
nullthrows "^1.1.1"
-"@parcel/transformer-inline-string@^2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-inline-string/-/transformer-inline-string-2.16.3.tgz#f081e4079878fd0a4f10792ec58961ca2af4c960"
- integrity sha512-oMjqqf/TfYQScy66ODEHWMInQYxpnlEpJDysT/OH4m+5+Q//Oh1hd6dl2g4SPmXUbgA9Y89ZfuifakoADpiCMg==
+"@parcel/transformer-inline-string@^2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-inline-string/-/transformer-inline-string-2.16.4.tgz#c16786e23499bcf2f3beaeaf583e46d22d423c83"
+ integrity sha512-Kr5YZbN3xeb3asvle9+Nso/Tqxy0I/mdV2oQC30NuVVP+PXbOD4fC24QtORyt0V1UX93KqgmXKl7G75767FcVg==
dependencies:
- "@parcel/plugin" "2.16.3"
+ "@parcel/plugin" "2.16.4"
-"@parcel/transformer-js@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.16.3.tgz#c7b0b8d06b5efdec0277beca7471b60ac25fdae3"
- integrity sha512-k83yElHagwDRYfza7BrADdf9NRGpizX3zOfctfEsQWh9mEZLNJENivP6ZLB9Aje9H0GaaSTiYU8VwOWLXbLgOw==
+"@parcel/transformer-js@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.16.4.tgz#91863d05668efc60d671acbf50161dee7210c468"
+ integrity sha512-FD2fdO6URwAGBPidb3x1dDgLBt972mko0LelcSU05aC/pcKaV9mbCtINbPul1MlStzkxDelhuImcCYIyerheVQ==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
"@parcel/source-map" "^2.1.1"
- "@parcel/utils" "2.16.3"
- "@parcel/workers" "2.16.3"
+ "@parcel/utils" "2.16.4"
+ "@parcel/workers" "2.16.4"
"@swc/helpers" "^0.5.0"
browserslist "^4.24.5"
nullthrows "^1.1.1"
regenerator-runtime "^0.14.1"
semver "^7.7.1"
-"@parcel/transformer-json@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.16.3.tgz#9f2e0f311a4a7e5bfcf8514f78baea0d05d8e362"
- integrity sha512-iT4IKGT95+S/7RBK1MUY/KxD8ad9FUlElF+w40NBLv4lm012wkYogFRhEHnyElPOByZL1aJ8GaVOGbZL9yuZfg==
+"@parcel/transformer-json@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.16.4.tgz#ae4d3e58fab6b574a6b07fb0b8365d798bcc1af4"
+ integrity sha512-pB3ZNqgokdkBCJ+4G0BrPYcIkyM9K1HVk0GvjzcLEFDKsoAp8BGEM68FzagFM/nVq9anYTshIaoh349GK0M/bg==
dependencies:
- "@parcel/plugin" "2.16.3"
+ "@parcel/plugin" "2.16.4"
json5 "^2.2.3"
-"@parcel/transformer-node@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-node/-/transformer-node-2.16.3.tgz#3bdb74d6f30019aec36df34a8e96183fd614b021"
- integrity sha512-FIbSphLisxmzwqE43ALsGeSPSYBA3ZE6xmhAIgwoFdeI6VfTSkCZnGhSqUhP3m9R55IuWm/+NP6BlePWADmkwg==
+"@parcel/transformer-node@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-node/-/transformer-node-2.16.4.tgz#87fab8af1998cd99f02b50233b815b8ee9f00c70"
+ integrity sha512-7t43CPGfMJk1LqFokwxHSsRi+kKC2QvDXaMtqiMShmk50LCwn81WgzuFvNhMwf6lSiBihWupGwF3Fqksg+aisg==
dependencies:
- "@parcel/plugin" "2.16.3"
+ "@parcel/plugin" "2.16.4"
-"@parcel/transformer-postcss@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.16.3.tgz#0d159b4b084889bdf03d5595ceeffca12421d9f1"
- integrity sha512-OMjU17OwPhPBK2LIzqQozBezolqI8jPgoT+CmoOkKr1GlgWMzCcHFpW6KQZxVVR+vI0lUEJp+RZc9MzhNndv4A==
+"@parcel/transformer-postcss@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.16.4.tgz#70b3cdc5d0a27bb48c5b5dcee2157483a26dc6ff"
+ integrity sha512-jfmh9ho03H+qwz9S1b/a/oaOmgfMovtHKYDweIGMjKULKIee3AFRqo8RZIOuUMjDuqHWK8SqQmjery4syFV3Xw==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
+ "@parcel/utils" "2.16.4"
clone "^2.1.2"
nullthrows "^1.1.1"
postcss-value-parser "^4.2.0"
semver "^7.7.1"
-"@parcel/transformer-posthtml@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.16.3.tgz#2ad23334de71ecafdbb58ee5f2cc5fab8af5e8cc"
- integrity sha512-y3iuM+yp8nPbt8sbQayPGR0saVGR6uj0aYr7hWoS0oUe9vZsH1mP3BTP6L6ABe/dZKU3QcFmMQgLwH6WC/apAA==
+"@parcel/transformer-posthtml@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.16.4.tgz#153428a26add6720df1863655b3b66019fdf5a61"
+ integrity sha512-+GXsmGx1L25KQGQnwclgEuQe1t4QU+IoDkgN+Ikj+EnQCOWG4/ts2VpMBeqP5F18ZT4cCSRafj6317o/2lSGJg==
dependencies:
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
-"@parcel/transformer-raw@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.16.3.tgz#440f623d0ba7b7a9cdb401942c42a42ae8508a2e"
- integrity sha512-Lha1+z75QbNAsxMAffp5K+ykGXEYSNOFUqI/8XtetYfuqIvS5s/OBkwsg8MWbjtPkbKo1F3EwNBaIAagw/BbIg==
+"@parcel/transformer-raw@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.16.4.tgz#02152b849133997833274b7a9fcba2172fbe7b8a"
+ integrity sha512-7WDUPq+bW11G9jKxaQIVL+NPGolV99oq/GXhpjYip0SaGaLzRCW7gEk60cftuk0O7MsDaX5jcAJm3G/AX+LJKg==
dependencies:
- "@parcel/plugin" "2.16.3"
+ "@parcel/plugin" "2.16.4"
-"@parcel/transformer-react-refresh-wrap@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.16.3.tgz#69e3073eab78e11820bd330f711482381a539a3b"
- integrity sha512-8rzO5iKF5bYrPUnbw4At0H7AwE+UHkuNNo385JL0VzXggrA0VsXsjjJwXVyhSeMvEbo2ioo/+nYUlazTQBABwA==
+"@parcel/transformer-react-refresh-wrap@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.16.4.tgz#a1e876072e5f14e03b1c1791dc89ee1b8742eb22"
+ integrity sha512-MiLNZrsGQJTANKKa4lzZyUbGj/en0Hms474mMdQkCBFg6GmjfmXwaMMgtTfPA3ZwSp2+3LeObCyca/f9B2gBZQ==
dependencies:
- "@parcel/error-overlay" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/error-overlay" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/utils" "2.16.4"
react-refresh "^0.16.0"
-"@parcel/transformer-svg@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.16.3.tgz#a28f94b0cfbf85f202eec5fc68c01404df30a331"
- integrity sha512-fDpUWSBZxt/R5pZUNd4gV/BX0c7B074lw/wmqwowjcwQU/QxhzPJBDlAsyTvOJ75PeJiQf/qFtnIK5bNwMoasA==
+"@parcel/transformer-svg@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.16.4.tgz#888840d106fb92a6a6145ce618bf47427e803944"
+ integrity sha512-0dm4cQr/WpfQP6N0xjFtwdLTxcONDfoLgTOMk4eNUWydHipSgmLtvUk/nOc/FWkwztRScfAObtZXOiPOd3Oy9A==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/plugin" "2.16.3"
- "@parcel/rust" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/plugin" "2.16.4"
+ "@parcel/rust" "2.16.4"
-"@parcel/types-internal@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/types-internal/-/types-internal-2.16.3.tgz#f9b414ced018ae7ed0a0c4290c6d0eb275b2cf44"
- integrity sha512-zi2GKdJHpNeW9sspTBfM68A9lekEztTWU8Dxs1ouPk90lfA0tfrMznAvkD5iJdKsM6usbgcqjjI8s+Ow8OrsBg==
+"@parcel/types-internal@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/types-internal/-/types-internal-2.16.4.tgz#ea87e092f2ced03adb0c3e8c1e445e39bb325409"
+ integrity sha512-PE6Qmt5cjzBxX+6MPLiF7r+twoC+V9Skt3zyuBQ+H1c0i9o07Bbz2NKX10nvlPukfmW6Fu/1RvTLkzBZR1bU6A==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/feature-flags" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/feature-flags" "2.16.4"
"@parcel/source-map" "^2.1.1"
utility-types "^3.11.0"
-"@parcel/types@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.16.3.tgz#9feeeba9a06f7be8b94c471a4da5fa5b7e65cf48"
- integrity sha512-aIJJFMif/A7u86UEt3sJPZ/F7suQW56ugiCp2Y2mYTPHpTJbI2Knk9yO4fkWHNO1BrH6a/VUWh7bWIOsQtzL1Q==
+"@parcel/types@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.16.4.tgz#e8a3d5f4404134763c4c240dd7bfeab2033be726"
+ integrity sha512-ctx4mBskZHXeDVHg4OjMwx18jfYH9BzI/7yqbDQVGvd5lyA+/oVVzYdpele2J2i2sSaJ87cA8nb57GDQ8kHAqA==
dependencies:
- "@parcel/types-internal" "2.16.3"
- "@parcel/workers" "2.16.3"
+ "@parcel/types-internal" "2.16.4"
+ "@parcel/workers" "2.16.4"
-"@parcel/utils@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.16.3.tgz#6f175c184e337d38d9735708c0bb1268e8df94ee"
- integrity sha512-g/yqVWSdZqPvTiS96dEK9MEl7q6w31u+luD5VGt6f9w6PQCpuVajhhDNuXf9uzDU/dL4sSZPKUhLteVZDqryHA==
+"@parcel/utils@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.16.4.tgz#d80a713358d10de7c3b37273aad499cbc051d540"
+ integrity sha512-lkmxQHcHyOWZLbV8t+h2CGZIkPiBurLm/TS5wNT7+tq0qt9KbVwL7FP2K93TbXhLMGTmpI79Bf3qKniPM167Mw==
dependencies:
- "@parcel/codeframe" "2.16.3"
- "@parcel/diagnostic" "2.16.3"
- "@parcel/logger" "2.16.3"
- "@parcel/markdown-ansi" "2.16.3"
- "@parcel/rust" "2.16.3"
+ "@parcel/codeframe" "2.16.4"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/logger" "2.16.4"
+ "@parcel/markdown-ansi" "2.16.4"
+ "@parcel/rust" "2.16.4"
"@parcel/source-map" "^2.1.1"
chalk "^4.1.2"
nullthrows "^1.1.1"
@@ -1197,16 +1204,16 @@
"@parcel/watcher-win32-ia32" "2.5.1"
"@parcel/watcher-win32-x64" "2.5.1"
-"@parcel/workers@2.16.3":
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.16.3.tgz#3ef399d2bd643f61d4344756c5f3dfb41c8b727c"
- integrity sha512-SxIXRnrlQFhw377wxWC5WIl1FL1Y9IedhUtuc7j3uac3tlbCQJJ+3rFr5/BDUknJbTktvVsPakE98fH7TIJyyw==
+"@parcel/workers@2.16.4":
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.16.4.tgz#80a6be911598cf42874af6041aec0bc1874f7305"
+ integrity sha512-dkBEWqnHXDZnRbTZouNt4uEGIslJT+V0c8OH1MPOfjISp1ucD6/u9ET8k9d/PxS9h1hL53og0SpBuuSEPLDl6A==
dependencies:
- "@parcel/diagnostic" "2.16.3"
- "@parcel/logger" "2.16.3"
- "@parcel/profiler" "2.16.3"
- "@parcel/types-internal" "2.16.3"
- "@parcel/utils" "2.16.3"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/logger" "2.16.4"
+ "@parcel/profiler" "2.16.4"
+ "@parcel/types-internal" "2.16.4"
+ "@parcel/utils" "2.16.4"
nullthrows "^1.1.1"
"@pkgjs/parseargs@^0.11.0":
@@ -2104,7 +2111,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
shebang-command "^2.0.0"
which "^2.0.1"
-css-tree@^3.1.0:
+css-tree@^3.0.0, css-tree@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.1.0.tgz#7aabc035f4e66b5c86f54570d55e05b1346eb0fd"
integrity sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==
@@ -2112,22 +2119,23 @@ css-tree@^3.1.0:
mdn-data "2.12.2"
source-map-js "^1.0.1"
-cssstyle@^5.3.4:
- version "5.3.4"
- resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-5.3.4.tgz#75635973c06998f36b3224cfc4b11b045e224f75"
- integrity sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==
+cssstyle@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-6.0.1.tgz#ca992a9dc7118d2a22adef96d01a1979c23ac779"
+ integrity sha512-IoJs7La+oFp/AB033wBStxNOJt4+9hHMxsXUPANcoXL2b3W4DZKghlJ2cI/eyeRZIQ9ysvYEorVhjrcYctWbog==
dependencies:
- "@asamuzakjp/css-color" "^4.1.0"
- "@csstools/css-syntax-patches-for-csstree" "1.0.14"
+ "@asamuzakjp/css-color" "^4.1.2"
+ "@csstools/css-syntax-patches-for-csstree" "^1.0.26"
css-tree "^3.1.0"
+ lru-cache "^11.2.5"
-data-urls@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-6.0.0.tgz#95a7943c8ac14c1d563b771f2621cc50e8ec7744"
- integrity sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==
+data-urls@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-7.0.0.tgz#6dce8b63226a1ecfdd907ce18a8ccfb1eee506d3"
+ integrity sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==
dependencies:
- whatwg-mimetype "^4.0.0"
- whatwg-url "^15.0.0"
+ whatwg-mimetype "^5.0.0"
+ whatwg-url "^16.0.0"
debounce@^1.2.0:
version "1.2.1"
@@ -2983,16 +2991,17 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
-jsdom@^27.4.0:
- version "27.4.0"
- resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-27.4.0.tgz#c36af2e43e1281a7e8bb8f255086435d177801f2"
- integrity sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==
- dependencies:
- "@acemir/cssom" "^0.9.28"
- "@asamuzakjp/dom-selector" "^6.7.6"
- "@exodus/bytes" "^1.6.0"
- cssstyle "^5.3.4"
- data-urls "^6.0.0"
+jsdom@^28.1.0:
+ version "28.1.0"
+ resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-28.1.0.tgz#ac4203e58fd24d7b0f34359ab00d6d9caebd4b62"
+ integrity sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==
+ dependencies:
+ "@acemir/cssom" "^0.9.31"
+ "@asamuzakjp/dom-selector" "^6.8.1"
+ "@bramus/specificity" "^2.4.2"
+ "@exodus/bytes" "^1.11.0"
+ cssstyle "^6.0.1"
+ data-urls "^7.0.0"
decimal.js "^10.6.0"
html-encoding-sniffer "^6.0.0"
http-proxy-agent "^7.0.2"
@@ -3002,11 +3011,11 @@ jsdom@^27.4.0:
saxes "^6.0.0"
symbol-tree "^3.2.4"
tough-cookie "^6.0.0"
+ undici "^7.21.0"
w3c-xmlserializer "^5.0.0"
- webidl-conversions "^8.0.0"
- whatwg-mimetype "^4.0.0"
- whatwg-url "^15.1.0"
- ws "^8.18.3"
+ webidl-conversions "^8.0.1"
+ whatwg-mimetype "^5.0.0"
+ whatwg-url "^16.0.0"
xml-name-validator "^5.0.0"
jsesc@^3.0.2:
@@ -3250,15 +3259,10 @@ lru-cache@^10.2.0:
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
-lru-cache@^11.2.2:
- version "11.2.2"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.2.tgz#40fd37edffcfae4b2940379c0722dc6eeaa75f24"
- integrity sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==
-
-lru-cache@^11.2.4:
- version "11.2.4"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.4.tgz#ecb523ebb0e6f4d837c807ad1abaea8e0619770d"
- integrity sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==
+lru-cache@^11.2.5, lru-cache@^11.2.6:
+ version "11.2.6"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.6.tgz#356bf8a29e88a7a2945507b31f6429a65a192c58"
+ integrity sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==
lru-cache@^5.1.1:
version "5.1.1"
@@ -3658,23 +3662,23 @@ package-json-from-dist@^1.0.0:
resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz"
integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
-parcel@^2.16.3:
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.16.3.tgz#6dc495713138d8f748ced14b8da77b3825e0491a"
- integrity sha512-N9jnwcTeVEaRjjJCCHmYfPCvjjJeHZuuO50qL4CCNcQX4RjwPuOaDft7hvTT2W8PIb4XhhZKDYB1lstZhXLJRQ==
- dependencies:
- "@parcel/config-default" "2.16.3"
- "@parcel/core" "2.16.3"
- "@parcel/diagnostic" "2.16.3"
- "@parcel/events" "2.16.3"
- "@parcel/feature-flags" "2.16.3"
- "@parcel/fs" "2.16.3"
- "@parcel/logger" "2.16.3"
- "@parcel/package-manager" "2.16.3"
- "@parcel/reporter-cli" "2.16.3"
- "@parcel/reporter-dev-server" "2.16.3"
- "@parcel/reporter-tracer" "2.16.3"
- "@parcel/utils" "2.16.3"
+parcel@^2.16.4:
+ version "2.16.4"
+ resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.16.4.tgz#a9219e35b97163e4fbee47241d641ed23c48c800"
+ integrity sha512-RQlrqs4ujYNJpTQi+dITqPKNhRWEqpjPd1YBcGp50Wy3FcJHpwu0/iRm7XWz2dKU/Bwp2qCcVYPIeEDYi2uOUw==
+ dependencies:
+ "@parcel/config-default" "2.16.4"
+ "@parcel/core" "2.16.4"
+ "@parcel/diagnostic" "2.16.4"
+ "@parcel/events" "2.16.4"
+ "@parcel/feature-flags" "2.16.4"
+ "@parcel/fs" "2.16.4"
+ "@parcel/logger" "2.16.4"
+ "@parcel/package-manager" "2.16.4"
+ "@parcel/reporter-cli" "2.16.4"
+ "@parcel/reporter-dev-server" "2.16.4"
+ "@parcel/reporter-tracer" "2.16.4"
+ "@parcel/utils" "2.16.4"
chalk "^4.1.2"
commander "^12.1.0"
get-port "^4.2.0"
@@ -3775,10 +3779,10 @@ prettier-plugin-organize-imports@^4.3.0:
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.3.0.tgz#e8d392e2040b3e5fc1476967d669487dde0eea76"
integrity sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==
-prettier@3.8.0:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.0.tgz#f72cf71505133f40cfa2ef77a2668cdc558fcd69"
- integrity sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==
+prettier@3.8.1:
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173"
+ integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==
pretty-format@^27.0.2:
version "27.5.1"
@@ -3811,9 +3815,9 @@ punycode@^2.3.1:
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
qs@^6.5.2:
- version "6.14.1"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.1.tgz#a41d85b9d3902f31d27861790506294881871159"
- integrity sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==
+ version "6.14.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.2.tgz#b5634cf9d9ad9898e31fba3504e866e8efb6798c"
+ integrity sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==
dependencies:
side-channel "^1.1.0"
@@ -4349,6 +4353,11 @@ undici-types@~7.8.0:
resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz"
integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==
+undici@^7.21.0:
+ version "7.22.0"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-7.22.0.tgz#7a82590a5908e504a47d85c60b0f89ca14240e60"
+ integrity sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==
+
unpipe@1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
@@ -4394,23 +4403,24 @@ weak-lru-cache@^1.2.2:
resolved "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz"
integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==
-webidl-conversions@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-8.0.0.tgz#821c92aa4f88d88a31264d887e244cb9655690c6"
- integrity sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==
+webidl-conversions@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-8.0.1.tgz#0657e571fe6f06fcb15ca50ed1fdbcb495cd1686"
+ integrity sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==
-whatwg-mimetype@^4.0.0:
- version "4.0.0"
- resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz"
- integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==
+whatwg-mimetype@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz#d8232895dbd527ceaee74efd4162008fb8a8cf48"
+ integrity sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==
-whatwg-url@^15.0.0, whatwg-url@^15.1.0:
- version "15.1.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-15.1.0.tgz#5c433439b9a5789eeb3806bbd0da89a8bd40b8d7"
- integrity sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==
+whatwg-url@^16.0.0:
+ version "16.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-16.0.0.tgz#73bafd41b77c54abfa40c4a4fd9c6103024e97d2"
+ integrity sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==
dependencies:
+ "@exodus/bytes" "^1.11.0"
tr46 "^6.0.0"
- webidl-conversions "^8.0.0"
+ webidl-conversions "^8.0.1"
which-module@^2.0.0:
version "2.0.1"
@@ -4485,11 +4495,6 @@ ws@^7.5.10:
resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz"
integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
-ws@^8.18.3:
- version "8.18.3"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472"
- integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==
-
xml-name-validator@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz"