#
tokens: 43291/50000 5/473 files (page 9/10)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 9 of 10. Use http://codebase.md/push-based/angular-toolkit-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .aiignore
├── .cursor
│   ├── flows
│   │   ├── component-refactoring
│   │   │   ├── 01-review-component.mdc
│   │   │   ├── 02-refactor-component.mdc
│   │   │   ├── 03-validate-component.mdc
│   │   │   └── angular-20.md
│   │   ├── ds-refactoring-flow
│   │   │   ├── 01-find-violations.mdc
│   │   │   ├── 01b-find-all-violations.mdc
│   │   │   ├── 02-plan-refactoring.mdc
│   │   │   ├── 02b-plan-refactoring-for-all-violations.mdc
│   │   │   ├── 03-fix-violations.mdc
│   │   │   ├── 03-non-viable-cases.mdc
│   │   │   ├── 04-validate-changes.mdc
│   │   │   ├── 05-prepare-report.mdc
│   │   │   └── clean-global-styles.mdc
│   │   └── README.md
│   └── mcp.json.example
├── .github
│   └── workflows
│       └── ci.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── assets
│   ├── entain-logo.png
│   └── entain.png
├── CONTRIBUTING.MD
├── docs
│   ├── architecture-internal-design.md
│   ├── component-refactoring-flow.md
│   ├── contracts.md
│   ├── ds-refactoring-flow.md
│   ├── getting-started.md
│   ├── README.md
│   ├── tools.md
│   └── writing-custom-tools.md
├── eslint.config.mjs
├── jest.config.ts
├── jest.preset.mjs
├── LICENSE
├── nx.json
├── package-lock.json
├── package.json
├── packages
│   ├── .gitkeep
│   ├── angular-mcp
│   │   ├── eslint.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── assets
│   │   │   │   └── .gitkeep
│   │   │   └── main.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── vitest.config.mts
│   │   └── webpack.config.cjs
│   ├── angular-mcp-server
│   │   ├── eslint.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.ts
│   │   │   └── lib
│   │   │       ├── angular-mcp-server.ts
│   │   │       ├── prompts
│   │   │       │   └── prompt-registry.ts
│   │   │       ├── tools
│   │   │       │   ├── ds
│   │   │       │   │   ├── component
│   │   │       │   │   │   ├── get-deprecated-css-classes.tool.ts
│   │   │       │   │   │   ├── get-ds-component-data.tool.ts
│   │   │       │   │   │   ├── list-ds-components.tool.ts
│   │   │       │   │   │   └── utils
│   │   │       │   │   │       ├── deprecated-css-helpers.ts
│   │   │       │   │   │       ├── doc-helpers.ts
│   │   │       │   │   │       ├── metadata-helpers.ts
│   │   │       │   │   │       └── paths-helpers.ts
│   │   │       │   │   ├── component-contract
│   │   │       │   │   │   ├── builder
│   │   │       │   │   │   │   ├── build-component-contract.tool.ts
│   │   │       │   │   │   │   ├── models
│   │   │       │   │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   │   └── types.ts
│   │   │       │   │   │   │   ├── spec
│   │   │       │   │   │   │   │   ├── css-match.spec.ts
│   │   │       │   │   │   │   │   ├── dom-slots.extractor.spec.ts
│   │   │       │   │   │   │   │   ├── element-helpers.spec.ts
│   │   │       │   │   │   │   │   ├── inline-styles.collector.spec.ts
│   │   │       │   │   │   │   │   ├── meta.generator.spec.ts
│   │   │       │   │   │   │   │   ├── public-api.extractor.spec.ts
│   │   │       │   │   │   │   │   ├── styles.collector.spec.ts
│   │   │       │   │   │   │   │   └── typescript-analyzer.spec.ts
│   │   │       │   │   │   │   └── utils
│   │   │       │   │   │   │       ├── build-contract.ts
│   │   │       │   │   │   │       ├── css-match.ts
│   │   │       │   │   │   │       ├── dom-slots.extractor.ts
│   │   │       │   │   │   │       ├── element-helpers.ts
│   │   │       │   │   │   │       ├── inline-styles.collector.ts
│   │   │       │   │   │   │       ├── meta.generator.ts
│   │   │       │   │   │   │       ├── public-api.extractor.ts
│   │   │       │   │   │   │       ├── styles.collector.ts
│   │   │       │   │   │   │       └── typescript-analyzer.ts
│   │   │       │   │   │   ├── diff
│   │   │       │   │   │   │   ├── diff-component-contract.tool.ts
│   │   │       │   │   │   │   ├── models
│   │   │       │   │   │   │   │   └── schema.ts
│   │   │       │   │   │   │   ├── spec
│   │   │       │   │   │   │   │   ├── diff-utils.spec.ts
│   │   │       │   │   │   │   │   └── dom-path-utils.spec.ts
│   │   │       │   │   │   │   └── utils
│   │   │       │   │   │   │       ├── diff-utils.ts
│   │   │       │   │   │   │       └── dom-path-utils.ts
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── list
│   │   │       │   │   │   │   ├── list-component-contracts.tool.ts
│   │   │       │   │   │   │   ├── models
│   │   │       │   │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   │   └── types.ts
│   │   │       │   │   │   │   ├── spec
│   │   │       │   │   │   │   │   └── contract-list-utils.spec.ts
│   │   │       │   │   │   │   └── utils
│   │   │       │   │   │   │       └── contract-list-utils.ts
│   │   │       │   │   │   └── shared
│   │   │       │   │   │       ├── models
│   │   │       │   │   │       │   └── types.ts
│   │   │       │   │   │       ├── spec
│   │   │       │   │   │       │   └── contract-file-ops.spec.ts
│   │   │       │   │   │       └── utils
│   │   │       │   │   │           └── contract-file-ops.ts
│   │   │       │   │   ├── component-usage-graph
│   │   │       │   │   │   ├── build-component-usage-graph.tool.ts
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── models
│   │   │       │   │   │   │   ├── config.ts
│   │   │       │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   └── types.ts
│   │   │       │   │   │   └── utils
│   │   │       │   │   │       ├── angular-parser.ts
│   │   │       │   │   │       ├── component-helpers.ts
│   │   │       │   │   │       ├── component-usage-graph-builder.ts
│   │   │       │   │   │       ├── path-resolver.ts
│   │   │       │   │   │       └── unified-ast-analyzer.ts
│   │   │       │   │   ├── ds.tools.ts
│   │   │       │   │   ├── project
│   │   │       │   │   │   ├── get-project-dependencies.tool.ts
│   │   │       │   │   │   ├── report-deprecated-css.tool.ts
│   │   │       │   │   │   └── utils
│   │   │       │   │   │       ├── dependencies-helpers.ts
│   │   │       │   │   │       └── styles-report-helpers.ts
│   │   │       │   │   ├── report-violations
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── models
│   │   │       │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   └── types.ts
│   │   │       │   │   │   ├── report-all-violations.tool.ts
│   │   │       │   │   │   └── report-violations.tool.ts
│   │   │       │   │   ├── shared
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── models
│   │   │       │   │   │   │   ├── input-schemas.model.ts
│   │   │       │   │   │   │   └── schema-helpers.ts
│   │   │       │   │   │   ├── utils
│   │   │       │   │   │   │   ├── component-validation.ts
│   │   │       │   │   │   │   ├── cross-platform-path.ts
│   │   │       │   │   │   │   ├── handler-helpers.ts
│   │   │       │   │   │   │   ├── output.utils.ts
│   │   │       │   │   │   │   └── regex-helpers.ts
│   │   │       │   │   │   └── violation-analysis
│   │   │       │   │   │       ├── base-analyzer.ts
│   │   │       │   │   │       ├── coverage-analyzer.ts
│   │   │       │   │   │       ├── formatters.ts
│   │   │       │   │   │       ├── index.ts
│   │   │       │   │   │       └── types.ts
│   │   │       │   │   └── tools.ts
│   │   │       │   ├── schema.ts
│   │   │       │   ├── tools.ts
│   │   │       │   ├── types.ts
│   │   │       │   └── utils.ts
│   │   │       └── validation
│   │   │           ├── angular-mcp-server-options.schema.ts
│   │   │           ├── ds-components-file-loader.validation.ts
│   │   │           ├── ds-components-file.validation.ts
│   │   │           ├── ds-components.schema.ts
│   │   │           └── file-existence.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.lib.json
│   │   ├── tsconfig.tsbuildinfo
│   │   └── vitest.config.mts
│   ├── minimal-repo
│   │   └── packages
│   │       ├── application
│   │       │   ├── angular.json
│   │       │   ├── code-pushup.config.ts
│   │       │   ├── src
│   │       │   │   ├── app
│   │       │   │   │   ├── app.component.ts
│   │       │   │   │   ├── app.config.ts
│   │       │   │   │   ├── app.routes.ts
│   │       │   │   │   ├── components
│   │       │   │   │   │   ├── refactoring-tests
│   │       │   │   │   │   │   ├── bad-alert-tooltip-input.component.ts
│   │       │   │   │   │   │   ├── bad-alert.component.ts
│   │       │   │   │   │   │   ├── bad-button-dropdown.component.ts
│   │       │   │   │   │   │   ├── bad-document.component.ts
│   │       │   │   │   │   │   ├── bad-global-this.component.ts
│   │       │   │   │   │   │   ├── bad-mixed-external-assets.component.css
│   │       │   │   │   │   │   ├── bad-mixed-external-assets.component.html
│   │       │   │   │   │   │   ├── bad-mixed-external-assets.component.ts
│   │       │   │   │   │   │   ├── bad-mixed-not-standalone.component.ts
│   │       │   │   │   │   │   ├── bad-mixed.component.ts
│   │       │   │   │   │   │   ├── bad-mixed.module.ts
│   │       │   │   │   │   │   ├── bad-modal-progress.component.ts
│   │       │   │   │   │   │   ├── bad-this-window-document.component.ts
│   │       │   │   │   │   │   ├── bad-window.component.ts
│   │       │   │   │   │   │   ├── complex-components
│   │       │   │   │   │   │   │   ├── first-case
│   │       │   │   │   │   │   │   │   ├── dashboard-demo.component.html
│   │       │   │   │   │   │   │   │   ├── dashboard-demo.component.scss
│   │       │   │   │   │   │   │   │   ├── dashboard-demo.component.ts
│   │       │   │   │   │   │   │   │   ├── dashboard-header.component.html
│   │       │   │   │   │   │   │   │   ├── dashboard-header.component.scss
│   │       │   │   │   │   │   │   │   └── dashboard-header.component.ts
│   │       │   │   │   │   │   │   ├── second-case
│   │       │   │   │   │   │   │   │   ├── complex-badge-widget.component.scss
│   │       │   │   │   │   │   │   │   ├── complex-badge-widget.component.ts
│   │       │   │   │   │   │   │   │   └── complex-widget-demo.component.ts
│   │       │   │   │   │   │   │   └── third-case
│   │       │   │   │   │   │   │       ├── product-card.component.scss
│   │       │   │   │   │   │   │       ├── product-card.component.ts
│   │       │   │   │   │   │   │       └── product-showcase.component.ts
│   │       │   │   │   │   │   ├── group-1
│   │       │   │   │   │   │   │   ├── bad-mixed-1.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-1.module.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-1.component.css
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-1.component.html
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-1.component.ts
│   │       │   │   │   │   │   │   └── bad-mixed-not-standalone-1.component.ts
│   │       │   │   │   │   │   ├── group-2
│   │       │   │   │   │   │   │   ├── bad-mixed-2.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-2.module.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-2.component.css
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-2.component.html
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-2.component.ts
│   │       │   │   │   │   │   │   └── bad-mixed-not-standalone-2.component.ts
│   │       │   │   │   │   │   ├── group-3
│   │       │   │   │   │   │   │   ├── bad-mixed-3.component.spec.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-3.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-3.module.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-3.component.css
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-3.component.html
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-3.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-not-standalone-3.component.ts
│   │       │   │   │   │   │   │   └── lazy-loader-3.component.ts
│   │       │   │   │   │   │   └── group-4
│   │       │   │   │   │   │       ├── multi-violation-test.component.html
│   │       │   │   │   │   │       ├── multi-violation-test.component.scss
│   │       │   │   │   │   │       └── multi-violation-test.component.ts
│   │       │   │   │   │   └── validation-tests
│   │       │   │   │   │       ├── circular-dependency.component.ts
│   │       │   │   │   │       ├── external-files-missing.component.ts
│   │       │   │   │   │       ├── invalid-lifecycle.component.ts
│   │       │   │   │   │       ├── invalid-pipe-usage.component.ts
│   │       │   │   │   │       ├── invalid-template-syntax.component.ts
│   │       │   │   │   │       ├── missing-imports.component.ts
│   │       │   │   │   │       ├── missing-method.component.ts
│   │       │   │   │   │       ├── README.md
│   │       │   │   │   │       ├── standalone-module-conflict.component.ts
│   │       │   │   │   │       ├── standalone-module-conflict.module.ts
│   │       │   │   │   │       ├── template-reference-error.component.ts
│   │       │   │   │   │       ├── type-mismatch.component.ts
│   │       │   │   │   │       ├── valid.component.ts
│   │       │   │   │   │       ├── wrong-decorator-usage.component.ts
│   │       │   │   │   │       └── wrong-property-binding.component.ts
│   │       │   │   │   └── styles
│   │       │   │   │       ├── bad-global-styles.scss
│   │       │   │   │       ├── base
│   │       │   │   │       │   ├── _reset.scss
│   │       │   │   │       │   └── base.scss
│   │       │   │   │       ├── components
│   │       │   │   │       │   └── components.scss
│   │       │   │   │       ├── extended-deprecated-styles.scss
│   │       │   │   │       ├── layout
│   │       │   │   │       │   └── layout.scss
│   │       │   │   │       ├── new-styles-1.scss
│   │       │   │   │       ├── new-styles-10.scss
│   │       │   │   │       ├── new-styles-2.scss
│   │       │   │   │       ├── new-styles-3.scss
│   │       │   │   │       ├── new-styles-4.scss
│   │       │   │   │       ├── new-styles-5.scss
│   │       │   │   │       ├── new-styles-6.scss
│   │       │   │   │       ├── new-styles-7.scss
│   │       │   │   │       ├── new-styles-8.scss
│   │       │   │   │       ├── new-styles-9.scss
│   │       │   │   │       ├── themes
│   │       │   │   │       │   └── themes.scss
│   │       │   │   │       └── utilities
│   │       │   │   │           └── utilities.scss
│   │       │   │   ├── index.html
│   │       │   │   ├── main.ts
│   │       │   │   └── styles.css
│   │       │   ├── tsconfig.app.json
│   │       │   ├── tsconfig.json
│   │       │   └── tsconfig.spec.json
│   │       └── design-system
│   │           ├── component-options.mjs
│   │           ├── storybook
│   │           │   └── card
│   │           │       └── card-tabs
│   │           │           └── overview.mdx
│   │           ├── storybook-host-app
│   │           │   └── src
│   │           │       └── components
│   │           │           ├── badge
│   │           │           │   ├── badge-tabs
│   │           │           │   │   ├── api.mdx
│   │           │           │   │   ├── examples.mdx
│   │           │           │   │   └── overview.mdx
│   │           │           │   ├── badge.component.mdx
│   │           │           │   └── badge.component.stories.ts
│   │           │           ├── modal
│   │           │           │   ├── demo-cdk-dialog-cmp.component.ts
│   │           │           │   ├── demo-modal-cmp.component.ts
│   │           │           │   ├── modal-tabs
│   │           │           │   │   ├── api.mdx
│   │           │           │   │   ├── examples.mdx
│   │           │           │   │   └── overview.mdx
│   │           │           │   ├── modal.component.mdx
│   │           │           │   └── modal.component.stories.ts
│   │           │           └── segmented-control
│   │           │               ├── segmented-control-tabs
│   │           │               │   ├── api.mdx
│   │           │               │   ├── examples.mdx
│   │           │               │   └── overview.mdx
│   │           │               ├── segmented-control.component.mdx
│   │           │               └── segmented-control.component.stories.ts
│   │           └── ui
│   │               ├── badge
│   │               │   ├── package.json
│   │               │   ├── project.json
│   │               │   └── src
│   │               │       └── badge.component.ts
│   │               ├── modal
│   │               │   ├── package.json
│   │               │   ├── project.json
│   │               │   └── src
│   │               │       ├── modal-content.component.ts
│   │               │       ├── modal-header
│   │               │       │   └── modal-header.component.ts
│   │               │       ├── modal-header-drag
│   │               │       │   └── modal-header-drag.component.ts
│   │               │       └── modal.component.ts
│   │               ├── rx-host-listener
│   │               │   ├── package.json
│   │               │   ├── project.json
│   │               │   └── src
│   │               │       └── rx-host-listener.ts
│   │               └── segmented-control
│   │                   ├── package.json
│   │                   ├── project.json
│   │                   └── src
│   │                       ├── segmented-control.component.html
│   │                       ├── segmented-control.component.ts
│   │                       ├── segmented-control.token.ts
│   │                       └── segmented-option.component.ts
│   └── shared
│       ├── angular-ast-utils
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── docs
│       │   │   └── angular-component-tree.md
│       │   ├── eslint.config.mjs
│       │   ├── jest.config.ts
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── constants.ts
│       │   │       ├── decorator-config.visitor.inline-styles.spec.ts
│       │   │       ├── decorator-config.visitor.spec.ts
│       │   │       ├── decorator-config.visitor.ts
│       │   │       ├── parse-component.ts
│       │   │       ├── schema.ts
│       │   │       ├── styles
│       │   │       │   └── utils.ts
│       │   │       ├── template
│       │   │       │   ├── noop-tmpl-visitor.ts
│       │   │       │   ├── template.walk.ts
│       │   │       │   ├── utils.spec.ts
│       │   │       │   ├── utils.ts
│       │   │       │   └── utils.unit.test.ts
│       │   │       ├── ts.walk.ts
│       │   │       ├── types.ts
│       │   │       └── utils.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       ├── DEPENDENCIES.md
│       ├── ds-component-coverage
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── docs
│       │   │   ├── examples
│       │   │   │   ├── report.json
│       │   │   │   └── report.md
│       │   │   ├── images
│       │   │   │   └── report-overview.png
│       │   │   └── README.md
│       │   ├── jest.config.ts
│       │   ├── mocks
│       │   │   └── fixtures
│       │   │       └── e2e
│       │   │           ├── asset-location
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── inl-styl-inl-tmpl
│       │   │           │   │   └── inl-styl-inl-tmpl.component.ts
│       │   │           │   ├── inl-styl-url-tmpl
│       │   │           │   │   ├── inl-styl-url-tmpl.component.html
│       │   │           │   │   └── inl-styl-url-tmpl.component.ts
│       │   │           │   ├── multi-url-styl-inl-tmpl
│       │   │           │   │   ├── multi-url-styl-inl-tmpl-1.component.css
│       │   │           │   │   ├── multi-url-styl-inl-tmpl-2.component.css
│       │   │           │   │   └── multi-url-styl-inl-tmpl.component.ts
│       │   │           │   ├── url-styl-inl-tmpl
│       │   │           │   │   ├── url-styl-inl-tmpl.component.css
│       │   │           │   │   └── url-styl-inl-tmpl.component.ts
│       │   │           │   ├── url-styl-single-inl-tmpl
│       │   │           │   │   ├── url-styl-inl-tmpl.component.ts
│       │   │           │   │   └── url-styl-single-inl-tmpl.component.css
│       │   │           │   └── url-styl-url-tmpl
│       │   │           │       ├── inl-styl-url-tmpl.component.css
│       │   │           │       ├── inl-styl-url-tmpl.component.html
│       │   │           │       └── inl-styl-url-tmpl.component.ts
│       │   │           ├── demo
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── prompt.md
│       │   │           │   └── src
│       │   │           │       ├── bad-button-dropdown.component.ts
│       │   │           │       ├── bad-modal-progress.component.ts
│       │   │           │       ├── mixed-external-assets.component.css
│       │   │           │       ├── mixed-external-assets.component.html
│       │   │           │       ├── mixed-external-assets.component.ts
│       │   │           │       └── sub-folder-1
│       │   │           │           ├── bad-alert.component.ts
│       │   │           │           ├── button.component.ts
│       │   │           │           └── sub-folder-2
│       │   │           │               ├── bad-alert-tooltip-input.component.ts
│       │   │           │               └── bad-mixed.component.ts
│       │   │           ├── line-number
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── inl-styl-single.component.ts
│       │   │           │   ├── inl-styl-span.component.ts
│       │   │           │   ├── inl-tmpl-single.component.ts
│       │   │           │   ├── inl-tmpl-span.component.ts
│       │   │           │   ├── url-style
│       │   │           │   │   ├── url-styl-single.component.css
│       │   │           │   │   ├── url-styl-single.component.ts
│       │   │           │   │   ├── url-styl-span.component.css
│       │   │           │   │   └── url-styl-span.component.ts
│       │   │           │   └── url-tmpl
│       │   │           │       ├── url-tmpl-single.component.html
│       │   │           │       ├── url-tmpl-single.component.ts
│       │   │           │       ├── url-tmpl-span.component.html
│       │   │           │       └── url-tmpl-span.component.ts
│       │   │           ├── style-format
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── inl-css.component.ts
│       │   │           │   ├── inl-scss.component.ts
│       │   │           │   ├── styles.css
│       │   │           │   ├── styles.scss
│       │   │           │   ├── url-css.component.ts
│       │   │           │   └── url-scss.component.ts
│       │   │           └── template-syntax
│       │   │               ├── class-attribute.component.ts
│       │   │               ├── class-binding.component.ts
│       │   │               ├── code-pushup.config.ts
│       │   │               └── ng-class-binding.component.ts
│       │   ├── package.json
│       │   ├── src
│       │   │   ├── core.config.ts
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── constants.ts
│       │   │       ├── ds-component-coverage.plugin.ts
│       │   │       ├── runner
│       │   │       │   ├── audits
│       │   │       │   │   └── ds-coverage
│       │   │       │   │       ├── class-definition.utils.ts
│       │   │       │   │       ├── class-definition.visitor.ts
│       │   │       │   │       ├── class-definition.visitor.unit.test.ts
│       │   │       │   │       ├── class-usage.utils.ts
│       │   │       │   │       ├── class-usage.visitor.spec.ts
│       │   │       │   │       ├── class-usage.visitor.ts
│       │   │       │   │       ├── constants.ts
│       │   │       │   │       ├── ds-coverage.audit.ts
│       │   │       │   │       ├── schema.ts
│       │   │       │   │       └── utils.ts
│       │   │       │   ├── create-runner.ts
│       │   │       │   └── schema.ts
│       │   │       └── utils.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       ├── LLMS.md
│       ├── models
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── cli.ts
│       │   │       ├── diagnostics.ts
│       │   │       └── mcp.ts
│       │   ├── tsconfig.json
│       │   └── tsconfig.lib.json
│       ├── styles-ast-utils
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── jest.config.ts
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── postcss-safe-parser.d.ts
│       │   │       ├── styles-ast-utils.spec.ts
│       │   │       ├── styles-ast-utils.ts
│       │   │       ├── stylesheet.parse.ts
│       │   │       ├── stylesheet.parse.unit.test.ts
│       │   │       ├── stylesheet.visitor.ts
│       │   │       ├── stylesheet.walk.ts
│       │   │       ├── types.ts
│       │   │       ├── utils.ts
│       │   │       └── utils.unit.test.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       ├── typescript-ast-utils
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── jest.config.ts
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── constants.ts
│       │   │       └── utils.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       └── utils
│           ├── .spec.swcrc
│           ├── ai
│           │   ├── API.md
│           │   ├── EXAMPLES.md
│           │   └── FUNCTIONS.md
│           ├── package.json
│           ├── README.md
│           ├── src
│           │   ├── index.ts
│           │   └── lib
│           │       ├── execute-process.ts
│           │       ├── execute-process.unit.test.ts
│           │       ├── file
│           │       │   ├── default-export-loader.spec.ts
│           │       │   ├── default-export-loader.ts
│           │       │   ├── file.resolver.ts
│           │       │   └── find-in-file.ts
│           │       ├── format-command-log.integration.test.ts
│           │       ├── format-command-log.ts
│           │       ├── logging.ts
│           │       └── utils.ts
│           ├── tsconfig.json
│           ├── tsconfig.lib.json
│           ├── tsconfig.spec.json
│           ├── vite.config.ts
│           └── vitest.config.mts
├── README.md
├── testing
│   ├── setup
│   │   ├── eslint.config.mjs
│   │   ├── eslint.next.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.d.ts
│   │   │   ├── index.mjs
│   │   │   └── memfs.constants.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.lib.json
│   │   ├── tsconfig.spec.json
│   │   ├── vitest.config.mts
│   │   └── vitest.integration.config.mts
│   ├── utils
│   │   ├── eslint.config.mjs
│   │   ├── eslint.next.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.ts
│   │   │   └── lib
│   │   │       ├── constants.ts
│   │   │       ├── e2e-setup.ts
│   │   │       ├── execute-process-helper.mock.ts
│   │   │       ├── execute-process.mock.mjs
│   │   │       ├── os-agnostic-paths.ts
│   │   │       ├── os-agnostic-paths.unit.test.ts
│   │   │       ├── source-file-from.code.ts
│   │   │       └── string.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.lib.json
│   │   ├── tsconfig.spec.json
│   │   ├── vite.config.ts
│   │   ├── vitest.config.mts
│   │   └── vitest.integration.config.mts
│   └── vitest-setup
│       ├── eslint.config.mjs
│       ├── eslint.next.config.mjs
│       ├── package.json
│       ├── README.md
│       ├── src
│       │   ├── index.ts
│       │   └── lib
│       │       ├── configuration.ts
│       │       └── fs-memfs.setup-file.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       ├── tsconfig.spec.json
│       ├── vite.config.ts
│       ├── vitest.config.mts
│       └── vitest.integration.config.mts
├── tools
│   ├── nx-advanced-profile.bin.js
│   ├── nx-advanced-profile.js
│   ├── nx-advanced-profile.postinstall.js
│   └── perf_hooks.patch.js
├── tsconfig.base.json
├── tsconfig.json
└── vitest.workspace.ts
```

# Files

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/src/lib/runner/audits/ds-coverage/class-usage.visitor.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { ClassUsageVisitor } from './class-usage.visitor';
  2 | import type {
  3 |   ParsedTemplate,
  4 |   ParseTemplateOptions,
  5 | } from '@angular/compiler' with { 'resolution-mode': 'import' };
  6 | 
  7 | describe('ClassCollectorVisitor', () => {
  8 |   let visitor: ClassUsageVisitor;
  9 |   let parseTemplate: (
 10 |     template: string,
 11 |     templateUrl: string,
 12 |     options?: ParseTemplateOptions,
 13 |   ) => ParsedTemplate;
 14 | 
 15 |   beforeAll(async () => {
 16 |     parseTemplate = (await import('@angular/compiler')).parseTemplate;
 17 |   });
 18 |   beforeEach(() => {
 19 |     visitor = new ClassUsageVisitor({
 20 |       componentName: 'CounterComponent',
 21 |       deprecatedCssClasses: ['count', 'count-badge', 'count-item'],
 22 |       docsUrl: 'my.doc#CounterComponent',
 23 |     });
 24 |   });
 25 | 
 26 |   it('should not find class when it is not a class-binding', () => {
 27 |     const template = `
 28 |                 <ms-list-item
 29 |                     [count]="link.count"
 30 |                     >
 31 |                 </ms-list-item>
 32 |              `;
 33 | 
 34 |     const ast = parseTemplate(template, 'template.html');
 35 | 
 36 |     ast.nodes.forEach((node) => node.visit(visitor));
 37 | 
 38 |     expect(visitor.getIssues()).toHaveLength(0);
 39 |   });
 40 | 
 41 |   it('<div class="count">1</div> should find node with css class', () => {
 42 |     const template = `<div class="count">1</div>`;
 43 | 
 44 |     const ast = parseTemplate(template, 'template.html');
 45 |     ast.nodes.forEach((node) => node.visit(visitor));
 46 | 
 47 |     expect(visitor.getIssues()).toStrictEqual([
 48 |       expect.objectContaining({
 49 |         message: expect.stringContaining('CounterComponent'),
 50 |       }),
 51 |     ]);
 52 |   });
 53 | 
 54 |   it('<div class="count">1</div> should find node within other css classes', () => {
 55 |     const template = `<div class="a count b">1</div>`;
 56 | 
 57 |     const ast = parseTemplate(template, 'template.html');
 58 |     ast.nodes.forEach((node) => node.visit(visitor));
 59 | 
 60 |     expect(visitor.getIssues()).toStrictEqual([
 61 |       expect.objectContaining({
 62 |         message: expect.stringContaining('CounterComponent'),
 63 |         severity: 'error',
 64 |         source: expect.objectContaining({
 65 |           file: 'template.html',
 66 |           position: expect.any(Object),
 67 |         }),
 68 |       }),
 69 |     ]);
 70 |   });
 71 | 
 72 |   it('<div [class.count]="true">2</div>', () => {
 73 |     const template = `<div [class.count]="true">2</div>`;
 74 | 
 75 |     const ast = parseTemplate(template, 'template.html');
 76 |     ast.nodes.forEach((node) => node.visit(visitor));
 77 | 
 78 |     expect(visitor.getIssues()).toStrictEqual([
 79 |       expect.objectContaining({
 80 |         message: expect.stringContaining('CounterComponent'),
 81 |         severity: 'error',
 82 |         source: expect.objectContaining({
 83 |           file: 'template.html',
 84 |           position: expect.any(Object),
 85 |         }),
 86 |       }),
 87 |     ]);
 88 |   });
 89 | 
 90 |   it('<div [class.count]="false">2</div> should find node with class-binding', () => {
 91 |     const template = `<div [class.count]="false">2</div>`;
 92 | 
 93 |     const ast = parseTemplate(template, 'template.html');
 94 |     ast.nodes.forEach((node) => node.visit(visitor));
 95 | 
 96 |     expect(visitor.getIssues()).toStrictEqual([
 97 |       expect.objectContaining({
 98 |         message: expect.stringContaining('CounterComponent'),
 99 |         severity: 'error',
100 |         source: expect.objectContaining({
101 |           file: 'template.html',
102 |           position: expect.any(Object),
103 |         }),
104 |       }),
105 |     ]);
106 |   });
107 | 
108 |   it('<div [class.a]="true">3</div> should not find not when other class is used in class-binding', () => {
109 |     const template = `<div [class.a]="true">3</div>`;
110 | 
111 |     const ast = parseTemplate(template, 'template.html');
112 |     ast.nodes.forEach((node) => node.visit(visitor));
113 | 
114 |     expect(visitor.getIssues()).toHaveLength(0);
115 |   });
116 | 
117 |   it('<div [class.a]="false">3</div> should not find node when other class is used in class-binding', () => {
118 |     const template = `<div [class.a]="false">3</div>`;
119 | 
120 |     const ast = parseTemplate(template, 'template.html');
121 |     ast.nodes.forEach((node) => node.visit(visitor));
122 | 
123 |     expect(visitor.getIssues()).toHaveLength(0);
124 |   });
125 | 
126 |   it("<div [ngClass]=\"['count', 'second']\">5</div> should find node when class is used in ngClass-binding", () => {
127 |     const template = `<div [ngClass]="['count', 'second']">5</div>`;
128 | 
129 |     const ast = parseTemplate(template, 'template.html');
130 |     ast.nodes.forEach((node) => node.visit(visitor));
131 | 
132 |     expect(visitor.getIssues()).toStrictEqual([
133 |       expect.objectContaining({
134 |         message: expect.stringContaining('CounterComponent'),
135 |         severity: 'error',
136 |         source: expect.objectContaining({
137 |           file: 'template.html',
138 |           position: expect.any(Object),
139 |         }),
140 |       }),
141 |     ]);
142 |   });
143 | 
144 |   it('<div [ngClass]="{ count: true, second: true, third: true }">6</div> should find node when class is used in ngClass-binding with object-binding', () => {
145 |     const template = `<div [ngClass]="{ count: true, second: true, third: true }">6</div>`;
146 | 
147 |     const ast = parseTemplate(template, 'template.html');
148 |     ast.nodes.forEach((node) => node.visit(visitor));
149 | 
150 |     expect(visitor.getIssues()).toStrictEqual([
151 |       expect.objectContaining({
152 |         message: expect.stringContaining('CounterComponent'),
153 |         severity: 'error',
154 |         source: expect.objectContaining({
155 |           file: 'template.html',
156 |           position: expect.any(Object),
157 |         }),
158 |       }),
159 |     ]);
160 |   });
161 | 
162 |   it('<div [ngClass]="{ count: false, second: true, third: true }">6</div> should find node when class is used in ngClass-binding with object-binding and other classes', () => {
163 |     const template = `<div [ngClass]="{ count: false, second: true, third: true }">6</div>`;
164 | 
165 |     const ast = parseTemplate(template, 'template.html');
166 |     ast.nodes.forEach((node) => node.visit(visitor));
167 | 
168 |     expect(visitor.getIssues()).toStrictEqual([
169 |       expect.objectContaining({
170 |         message: expect.stringContaining('CounterComponent'),
171 |         severity: 'error',
172 |         source: expect.objectContaining({
173 |           file: 'template.html',
174 |           position: expect.any(Object),
175 |         }),
176 |       }),
177 |     ]);
178 |   });
179 | 
180 |   it('<div [ngClass]="{ \'count second\': true }">7</div> should find node when class is used in ngClass-binding with object-binding and condensed signature', () => {
181 |     const template = `<div [ngClass]="{ 'count second': true }">7</div>`;
182 | 
183 |     const ast = parseTemplate(template, 'template.html');
184 |     ast.nodes.forEach((node) => node.visit(visitor));
185 | 
186 |     expect(visitor.getIssues()).toStrictEqual([
187 |       expect.objectContaining({
188 |         message: expect.stringContaining('CounterComponent'),
189 |         severity: 'error',
190 |         source: expect.objectContaining({
191 |           file: 'template.html',
192 |           position: expect.any(Object),
193 |         }),
194 |       }),
195 |     ]);
196 |   });
197 | 
198 |   it('<div [ngClass]="{ \'count second\': false }">7</div>', () => {
199 |     const template = `<div [ngClass]="{ 'count second': false }">7</div>`;
200 | 
201 |     const ast = parseTemplate(template, 'template.html');
202 |     ast.nodes.forEach((node) => node.visit(visitor));
203 | 
204 |     expect(visitor.getIssues()).toStrictEqual([
205 |       expect.objectContaining({
206 |         message: expect.stringContaining('CounterComponent'),
207 |         severity: 'error',
208 |         source: expect.objectContaining({
209 |           file: 'template.html',
210 |           position: expect.any(Object),
211 |         }),
212 |       }),
213 |     ]);
214 |   });
215 | 
216 |   it('should find all nodes in @if-blocks', () => {
217 |     const template = `
218 |             @if (true){
219 |               <div id="1" class="count"></div>
220 |             }
221 |              <div>
222 |               <span>
223 |                  @if (true){
224 |                   <div id="2" class="count"></div>
225 |                   }
226 |               </span>
227 |             </div>
228 |       `;
229 | 
230 |     const ast = parseTemplate(template, 'template.html');
231 |     ast.nodes.forEach((node) => node.visit(visitor));
232 | 
233 |     expect(visitor.getIssues()).toHaveLength(2);
234 |     expect(visitor.getIssues()).toEqual([
235 |       expect.objectContaining({
236 |         message: expect.stringContaining('CounterComponent'),
237 |         severity: 'error',
238 |         source: expect.objectContaining({
239 |           file: 'template.html',
240 |           position: expect.any(Object),
241 |         }),
242 |       }),
243 |       expect.objectContaining({
244 |         message: expect.stringContaining('CounterComponent'),
245 |         severity: 'error',
246 |         source: expect.objectContaining({
247 |           file: 'template.html',
248 |           position: expect.any(Object),
249 |         }),
250 |       }),
251 |     ]);
252 |   });
253 | 
254 |   it('should find all nodes with *ngIf', () => {
255 |     const template = `
256 |           <ng-container *ngIf="true">
257 |            <div id="1" class="count"></div>
258 |           </ng-container>
259 |            <div>
260 |           <span>
261 | 
262 |                 <div *ngIf="true" id="2" class="count"></div>
263 | 
264 |           </span>
265 |         </div>
266 |       `;
267 | 
268 |     const ast = parseTemplate(template, 'template.html');
269 |     ast.nodes.forEach((node) => node.visit(visitor));
270 | 
271 |     expect(visitor.getIssues()).toHaveLength(2);
272 |     expect(visitor.getIssues()).toEqual([
273 |       expect.objectContaining({
274 |         message: expect.stringContaining('CounterComponent'),
275 |         severity: 'error',
276 |         source: expect.objectContaining({
277 |           file: 'template.html',
278 |           position: expect.any(Object),
279 |         }),
280 |       }),
281 |       expect.objectContaining({
282 |         message: expect.stringContaining('CounterComponent'),
283 |         severity: 'error',
284 |         source: expect.objectContaining({
285 |           file: 'template.html',
286 |           position: expect.any(Object),
287 |         }),
288 |       }),
289 |     ]);
290 |   });
291 | 
292 |   it('should find all nodes in @for-block', () => {
293 |     const template = `
294 |         @for (item of items; track item.name) {
295 |           <div id="1" class="count"></div>
296 |         }
297 |         <div>
298 |           <span>
299 |             @for (item of items; track item.name) {
300 |               <div id="2" class="count"></div>
301 |             }
302 |           </span>
303 |         </div>
304 |       `;
305 | 
306 |     const ast = parseTemplate(template, 'template.html');
307 |     ast.nodes.forEach((node) => node.visit(visitor));
308 | 
309 |     expect(visitor.getIssues()).toHaveLength(2);
310 |     expect(visitor.getIssues()).toEqual([
311 |       expect.objectContaining({
312 |         message: expect.stringContaining('CounterComponent'),
313 |         severity: 'error',
314 |         source: expect.objectContaining({
315 |           file: 'template.html',
316 |           position: expect.any(Object),
317 |         }),
318 |       }),
319 |       expect.objectContaining({
320 |         message: expect.stringContaining('CounterComponent'),
321 |         severity: 'error',
322 |         source: expect.objectContaining({
323 |           file: 'template.html',
324 |           position: expect.any(Object),
325 |         }),
326 |       }),
327 |     ]);
328 |   });
329 | 
330 |   it('should find all nodes with *ngFor', () => {
331 |     const template = `
332 |         <div id="1" *ngFor="let item of [1,2,3]" class="count"></div>
333 |       `;
334 | 
335 |     const ast = parseTemplate(template, 'template.html');
336 |     ast.nodes.forEach((node) => node.visit(visitor));
337 | 
338 |     expect(visitor.getIssues()).toStrictEqual([
339 |       expect.objectContaining({
340 |         message: expect.stringContaining('CounterComponent'),
341 |         severity: 'error',
342 |         source: expect.objectContaining({
343 |           file: 'template.html',
344 |           position: expect.any(Object),
345 |         }),
346 |       }),
347 |     ]);
348 |   });
349 | 
350 |   it('should find all nodes with *switch', () => {
351 |     const template = `
352 |         <ng-container *ngSwitchCase="userPermissions">
353 |           <ng-container *ngSwitchCase="'admin'">
354 |             <div id="1" class="count"></div>
355 |           </ng-container>
356 |            <ng-container *ngSwitchCase="'reviewer'">
357 | 
358 |           </ng-container>
359 |             <ng-container *ngSwitchDefault>
360 | 
361 |           </ng-container>
362 |         </ng-container>
363 |       `;
364 | 
365 |     const ast = parseTemplate(template, 'template.html');
366 |     ast.nodes.forEach((node) => node.visit(visitor));
367 | 
368 |     expect(visitor.getIssues()).toStrictEqual([
369 |       expect.objectContaining({
370 |         message: expect.stringContaining('CounterComponent'),
371 |         severity: 'error',
372 |         source: expect.objectContaining({
373 |           file: 'template.html',
374 |           position: expect.any(Object),
375 |         }),
376 |       }),
377 |     ]);
378 |   });
379 | 
380 |   it('should find all nodes inside @switch', () => {
381 |     const template = `
382 |           @switch (userPermissions) {
383 |             @case ('admin') {
384 |               <div id="1" class="count"></div>
385 |             }
386 |             @case ('reviewer') {
387 | 
388 |             }
389 |             @case ('editor') {
390 | 
391 |             }
392 |             @default {
393 | 
394 |             }
395 |           }
396 |         `;
397 | 
398 |     const ast = parseTemplate(template, 'template.html');
399 |     ast.nodes.forEach((node) => node.visit(visitor));
400 | 
401 |     expect(visitor.getIssues()).toStrictEqual([
402 |       expect.objectContaining({
403 |         message: expect.stringContaining('CounterComponent'),
404 |         severity: 'error',
405 |         source: expect.objectContaining({
406 |           file: 'template.html',
407 |           position: expect.any(Object),
408 |         }),
409 |       }),
410 |     ]);
411 |   });
412 | 
413 |   it('should find all nodes inside @defer', () => {
414 |     const template = `
415 |           @defer {
416 |               <div id="1" class="count"></div>
417 |           }
418 |         `;
419 | 
420 |     const ast = parseTemplate(template, 'template.html');
421 |     ast.nodes.forEach((node) => node.visit(visitor));
422 | 
423 |     expect(visitor.getIssues()).toStrictEqual([
424 |       expect.objectContaining({
425 |         message: expect.stringContaining('CounterComponent'),
426 |         severity: 'error',
427 |         source: expect.objectContaining({
428 |           file: 'template.html',
429 |           position: expect.any(Object),
430 |         }),
431 |       }),
432 |     ]);
433 |   });
434 | 
435 |   it('should find deprecated classes in interpolated class attributes', () => {
436 |     const template = `<div class="count count-{{ size() }} other-class">Content</div>`;
437 | 
438 |     const ast = parseTemplate(template, 'template.html');
439 |     ast.nodes.forEach((node) => node.visit(visitor));
440 | 
441 |     expect(visitor.getIssues()).toStrictEqual([
442 |       expect.objectContaining({
443 |         message: expect.stringContaining('CounterComponent'),
444 |         severity: 'error',
445 |         source: expect.objectContaining({
446 |           file: 'template.html',
447 |           position: expect.any(Object),
448 |         }),
449 |       }),
450 |     ]);
451 |   });
452 | 
453 |   // Deduplication tests
454 |   describe('deduplication', () => {
455 |     it('should deduplicate multiple deprecated classes in same class attribute', () => {
456 |       const template = `<div class="count count-badge other-class">Content</div>`;
457 | 
458 |       const ast = parseTemplate(template, 'template.html');
459 |       ast.nodes.forEach((node) => node.visit(visitor));
460 | 
461 |       expect(visitor.getIssues()).toHaveLength(1);
462 |       const message = visitor.getIssues()[0].message;
463 |       expect(message).toContain('count, count-badge');
464 |       expect(message).toContain('CounterComponent');
465 |       expect(visitor.getIssues()[0]).toEqual(
466 |         expect.objectContaining({
467 |           severity: 'error',
468 |           source: expect.objectContaining({
469 |             file: 'template.html',
470 |             position: expect.any(Object),
471 |           }),
472 |         }),
473 |       );
474 |     });
475 | 
476 |     it('should deduplicate multiple deprecated classes in ngClass array', () => {
477 |       const template = `<div [ngClass]="['count', 'count-badge', 'other-class']">Content</div>`;
478 | 
479 |       const ast = parseTemplate(template, 'template.html');
480 |       ast.nodes.forEach((node) => node.visit(visitor));
481 | 
482 |       expect(visitor.getIssues()).toHaveLength(1);
483 |       const message = visitor.getIssues()[0].message;
484 |       expect(message).toContain('count, count-badge');
485 |       expect(message).toContain('CounterComponent');
486 |       expect(visitor.getIssues()[0]).toEqual(
487 |         expect.objectContaining({
488 |           severity: 'error',
489 |           source: expect.objectContaining({
490 |             file: 'template.html',
491 |             position: expect.any(Object),
492 |           }),
493 |         }),
494 |       );
495 |     });
496 | 
497 |     it('should deduplicate multiple deprecated classes in ngClass object', () => {
498 |       const template = `<div [ngClass]="{ count: true, 'count-badge': true, other: false }">Content</div>`;
499 | 
500 |       const ast = parseTemplate(template, 'template.html');
501 |       ast.nodes.forEach((node) => node.visit(visitor));
502 | 
503 |       expect(visitor.getIssues()).toHaveLength(1);
504 |       const message = visitor.getIssues()[0].message;
505 |       expect(message).toContain('count, count-badge');
506 |       expect(message).toContain('CounterComponent');
507 |       expect(visitor.getIssues()[0]).toEqual(
508 |         expect.objectContaining({
509 |           severity: 'error',
510 |           source: expect.objectContaining({
511 |             file: 'template.html',
512 |             position: expect.any(Object),
513 |           }),
514 |         }),
515 |       );
516 |     });
517 | 
518 |     it('should still create single issue for single deprecated class', () => {
519 |       const template = `<div class="count other-class">Content</div>`;
520 | 
521 |       const ast = parseTemplate(template, 'template.html');
522 |       ast.nodes.forEach((node) => node.visit(visitor));
523 | 
524 |       expect(visitor.getIssues()).toHaveLength(1);
525 |       const message = visitor.getIssues()[0].message;
526 |       expect(message).toContain('count');
527 |       expect(message).not.toContain(',');
528 |       expect(message).toContain('CounterComponent');
529 |       expect(visitor.getIssues()[0]).toEqual(
530 |         expect.objectContaining({
531 |           severity: 'error',
532 |           source: expect.objectContaining({
533 |             file: 'template.html',
534 |             position: expect.any(Object),
535 |           }),
536 |         }),
537 |       );
538 |     });
539 | 
540 |     it('should deduplicate three deprecated classes in same class attribute', () => {
541 |       const template = `<div class="count count-badge count-item other-class">Content</div>`;
542 | 
543 |       const ast = parseTemplate(template, 'template.html');
544 |       ast.nodes.forEach((node) => node.visit(visitor));
545 | 
546 |       expect(visitor.getIssues()).toHaveLength(1);
547 |       const message = visitor.getIssues()[0].message;
548 |       expect(message).toContain('count, count-badge, count-item');
549 |       expect(message).toContain('CounterComponent');
550 |       expect(visitor.getIssues()[0]).toEqual(
551 |         expect.objectContaining({
552 |           severity: 'error',
553 |           source: expect.objectContaining({
554 |             file: 'template.html',
555 |             position: expect.any(Object),
556 |           }),
557 |         }),
558 |       );
559 |     });
560 |   });
561 | });
562 | 
```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/src/lib/template/utils.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import {
  2 |   extractClassNamesFromNgClassAST,
  3 |   ngClassContainsClass,
  4 |   ngClassesIncludeClassName,
  5 | } from './utils';
  6 | import type {
  7 |   ASTWithSource,
  8 |   TmplAstElement,
  9 | } from '@angular/compiler' with { 'resolution-mode': 'import' };
 10 | 
 11 | let parseTemplate: typeof import('@angular/compiler').parseTemplate;
 12 | 
 13 | beforeAll(async () => {
 14 |   parseTemplate = (await import('@angular/compiler')).parseTemplate;
 15 | });
 16 | 
 17 | function parseNgClassExpression(expression: string): ASTWithSource {
 18 |   const template = `<div [ngClass]="${expression}"></div>`;
 19 |   const result = parseTemplate(template, 'test.html');
 20 |   const element = result.nodes[0] as TmplAstElement;
 21 |   const ngClassInput = element.inputs.find((input) => input.name === 'ngClass');
 22 |   return ngClassInput?.value as ASTWithSource;
 23 | }
 24 | 
 25 | describe('extractClassNamesFromNgClassAST', () => {
 26 |   it('should extract classes from array literals', () => {
 27 |     const expression = "['btn', 'btn-primary', someVariable]";
 28 |     const astWithSource = parseNgClassExpression(expression);
 29 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
 30 |       'btn',
 31 |       'btn-primary',
 32 |       'other',
 33 |     ]);
 34 | 
 35 |     expect(result).toEqual(['btn', 'btn-primary']);
 36 |   });
 37 | 
 38 |   it('should extract classes from object literals', () => {
 39 |     const expression =
 40 |       "{ 'btn': true, 'btn-primary': isActive, 'other-class': false }";
 41 |     const astWithSource = parseNgClassExpression(expression);
 42 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
 43 |       'btn',
 44 |       'btn-primary',
 45 |       'other-class',
 46 |     ]);
 47 | 
 48 |     expect(result).toEqual(['btn', 'btn-primary', 'other-class']);
 49 |   });
 50 | 
 51 |   it('should extract classes from string literals', () => {
 52 |     const expression = "'btn btn-primary active'";
 53 |     const astWithSource = parseNgClassExpression(expression);
 54 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
 55 |       'btn',
 56 |       'btn-primary',
 57 |       'active',
 58 |     ]);
 59 | 
 60 |     expect(result).toEqual(['btn', 'btn-primary', 'active']);
 61 |   });
 62 | 
 63 |   it('should extract classes from ternary expressions without false positives from conditions', () => {
 64 |     const expression =
 65 |       "option?.logo?.toLowerCase() === 'card' ? 'card-special' : 'card-normal'";
 66 |     const astWithSource = parseNgClassExpression(expression);
 67 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
 68 |       'card',
 69 |       'card-special',
 70 |       'card-normal',
 71 |     ]);
 72 | 
 73 |     expect(result).toEqual(['card-special', 'card-normal']);
 74 |   });
 75 | 
 76 |   it('should not extract classes from binary comparison expressions', () => {
 77 |     const expression = "someValue === 'card' && otherValue !== 'btn'";
 78 |     const astWithSource = parseNgClassExpression(expression);
 79 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
 80 |       'card',
 81 |       'btn',
 82 |     ]);
 83 | 
 84 |     expect(result).toEqual([]);
 85 |   });
 86 | 
 87 |   it('should handle complex nested expressions', () => {
 88 |     const expression =
 89 |       "[option?.logo?.toLowerCase() === 'card' ? 'card-active' : '', 'base-class']";
 90 |     const astWithSource = parseNgClassExpression(expression);
 91 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
 92 |       'card',
 93 |       'card-active',
 94 |       'base-class',
 95 |     ]);
 96 | 
 97 |     expect(result).toEqual(['card-active', 'base-class']);
 98 |   });
 99 | 
100 |   it('should handle object with conditional values', () => {
101 |     const expression =
102 |       "{ 'card': option?.logo?.toLowerCase() === 'card', 'btn': isButton }";
103 |     const astWithSource = parseNgClassExpression(expression);
104 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
105 |       'card',
106 |       'btn',
107 |     ]);
108 | 
109 |     expect(result).toEqual(['card', 'btn']);
110 |   });
111 | 
112 |   it('should handle spaced class names in object keys', () => {
113 |     const expression = "{ 'card special': true, 'btn primary': false }";
114 |     const astWithSource = parseNgClassExpression(expression);
115 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
116 |       'card',
117 |       'special',
118 |       'btn',
119 |       'primary',
120 |     ]);
121 | 
122 |     expect(result).toEqual(['card', 'special', 'btn', 'primary']);
123 |   });
124 | 
125 |   it('should return empty array for non-matching classes', () => {
126 |     const expression = "['other', 'different']";
127 |     const astWithSource = parseNgClassExpression(expression);
128 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
129 |       'card',
130 |       'btn',
131 |     ]);
132 | 
133 |     expect(result).toEqual([]);
134 |   });
135 | 
136 |   it('should remove duplicates', () => {
137 |     const expression = "['card', 'card', 'btn']";
138 |     const astWithSource = parseNgClassExpression(expression);
139 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
140 |       'card',
141 |       'btn',
142 |     ]);
143 | 
144 |     expect(result).toEqual(['card', 'btn']);
145 |   });
146 | });
147 | 
148 | describe('ngClassContainsClass', () => {
149 |   it('should return true when class is found in AST', () => {
150 |     const expression = "['btn', 'btn-primary']";
151 |     const astWithSource = parseNgClassExpression(expression);
152 | 
153 |     expect(ngClassContainsClass(astWithSource, 'btn')).toBe(true);
154 |     expect(ngClassContainsClass(astWithSource, 'btn-primary')).toBe(true);
155 |   });
156 | 
157 |   it('should return false when class is not found in AST', () => {
158 |     const expression = "['other', 'different']";
159 |     const astWithSource = parseNgClassExpression(expression);
160 | 
161 |     expect(ngClassContainsClass(astWithSource, 'btn')).toBe(false);
162 |   });
163 | 
164 |   it('should return false for classes in comparisons', () => {
165 |     const expression =
166 |       "option?.logo?.toLowerCase() === 'card' ? 'active' : 'inactive'";
167 |     const astWithSource = parseNgClassExpression(expression);
168 | 
169 |     // Should not find 'card' since it's in a comparison, not a class assignment
170 |     expect(ngClassContainsClass(astWithSource, 'card')).toBe(false);
171 |     expect(ngClassContainsClass(astWithSource, 'active')).toBe(true);
172 |   });
173 | });
174 | 
175 | describe('AST-based ngClass parsing integration tests', () => {
176 |   it('should handle the original problem case correctly', () => {
177 |     const expression =
178 |       "[option?.logo?.toLowerCase(), option?.logo?.toLowerCase() == 'card' ? mergedCardLogoClass : '']";
179 |     const astWithSource = parseNgClassExpression(expression);
180 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, ['card']);
181 | 
182 |     // Should NOT find 'card' from the comparison
183 |     expect(result).toEqual([]);
184 |   });
185 | 
186 |   it('should find card when actually used as a class', () => {
187 |     const expression = "['card', 'other-class']";
188 |     const astWithSource = parseNgClassExpression(expression);
189 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, ['card']);
190 | 
191 |     expect(result).toEqual(['card']);
192 |   });
193 | 
194 |   it('should handle complex real-world scenarios', () => {
195 |     const expression =
196 |       "{ 'card': isCard, 'btn': isButton, 'active': option?.logo?.toLowerCase() === 'card' }";
197 |     const astWithSource = parseNgClassExpression(expression);
198 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
199 |       'card',
200 |       'btn',
201 |     ]);
202 | 
203 |     expect(result).toEqual(['card', 'btn']);
204 |   });
205 | });
206 | 
207 | describe('AST-based class binding parsing', () => {
208 |   function parseClassExpression(expression: string): ASTWithSource {
209 |     const template = `<div [class]="${expression}"></div>`;
210 |     const result = parseTemplate(template, 'test.html');
211 |     const element = result.nodes[0] as TmplAstElement;
212 |     const classInput = element.inputs.find((input) => input.name === 'class');
213 |     return classInput?.value as ASTWithSource;
214 |   }
215 | 
216 |   it('should work the same for [class] bindings with false positive avoidance', () => {
217 |     const expression =
218 |       "option?.logo?.toLowerCase() == 'card' ? 'card-special' : 'other'";
219 |     const astWithSource = parseClassExpression(expression);
220 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
221 |       'card',
222 |       'card-special',
223 |     ]);
224 | 
225 |     expect(result).toEqual(['card-special']);
226 |   });
227 | 
228 |   it('should handle simple string literals in [class] bindings', () => {
229 |     const expression = "'card btn-primary'";
230 |     const astWithSource = parseClassExpression(expression);
231 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
232 |       'card',
233 |       'btn-primary',
234 |       'other',
235 |     ]);
236 | 
237 |     expect(result).toEqual(['card', 'btn-primary']);
238 |   });
239 | 
240 |   it('should handle ternary expressions in [class] bindings', () => {
241 |     const expression = "isActive ? 'card active' : 'card inactive'";
242 |     const astWithSource = parseClassExpression(expression);
243 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
244 |       'card',
245 |       'active',
246 |       'inactive',
247 |     ]);
248 | 
249 |     expect(result).toEqual(['card', 'active', 'inactive']);
250 |   });
251 | });
252 | 
253 | describe('AST-based interpolated class parsing', () => {
254 |   function parseInterpolatedClassExpression(classValue: string): ASTWithSource {
255 |     const template = `<div class="${classValue}"></div>`;
256 |     const result = parseTemplate(template, 'test.html');
257 |     const element = result.nodes[0] as TmplAstElement;
258 |     const classInput = element.inputs.find((input) => input.name === 'class');
259 |     return classInput?.value as ASTWithSource;
260 |   }
261 | 
262 |   it('should extract classes from interpolated class attributes', () => {
263 |     const classValue = 'count count-{{ size() }} other-class';
264 |     const astWithSource = parseInterpolatedClassExpression(classValue);
265 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
266 |       'count',
267 |       'other-class',
268 |       'different',
269 |     ]);
270 | 
271 |     expect(result).toEqual(['count', 'other-class']);
272 |   });
273 | 
274 |   it('should handle interpolation with multiple dynamic parts', () => {
275 |     const classValue = 'prefix {{ type }} middle {{ state }} suffix';
276 |     const astWithSource = parseInterpolatedClassExpression(classValue);
277 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
278 |       'prefix',
279 |       'middle',
280 |       'suffix',
281 |     ]);
282 | 
283 |     expect(result).toEqual(['prefix', 'middle', 'suffix']);
284 |   });
285 | 
286 |   it('should handle interpolation with only static classes', () => {
287 |     const classValue = 'btn btn-primary active';
288 |     const astWithSource = parseInterpolatedClassExpression(classValue);
289 | 
290 |     // Static class attributes without interpolation don't create class inputs
291 |     // They are handled as static attributes, not dynamic bindings
292 |     expect(astWithSource).toBeUndefined();
293 |   });
294 | 
295 |   it('should avoid false positives from dynamic expressions in interpolation', () => {
296 |     const classValue = "base-class {{ condition ? 'card' : 'other' }}";
297 |     const astWithSource = parseInterpolatedClassExpression(classValue);
298 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
299 |       'base-class',
300 |       'card',
301 |       'other',
302 |     ]);
303 | 
304 |     expect(result).toEqual(['base-class']);
305 |   });
306 | 
307 |   it('should handle the exact failing test case', () => {
308 |     const classValue = 'count count-{{ size() }} other-class';
309 |     const astWithSource = parseInterpolatedClassExpression(classValue);
310 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
311 |       'count',
312 |     ]);
313 | 
314 |     expect(result).toEqual(['count']);
315 |   });
316 | });
317 | 
318 | describe('Real-world ngClass patterns from monorepo', () => {
319 |   it('should handle complex object-style ngClass with multiple conditions', () => {
320 |     // Based on promo filter popup component
321 |     const expression = `{ 
322 |       'disabled': selectedFilterIndexes?.totalCount === 0, 
323 |       'pill-with-badge-v2': isOfferPageEnhanced,
324 |       'ml-2': true,
325 |       'promo-filter-apply': isOfferPageEnhanced 
326 |     }`;
327 |     const astWithSource = parseNgClassExpression(expression);
328 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
329 |       'disabled',
330 |       'pill-with-badge-v2',
331 |       'ml-2',
332 |       'promo-filter-apply',
333 |       'btn-primary',
334 |     ]);
335 | 
336 |     expect(result).toEqual([
337 |       'disabled',
338 |       'pill-with-badge-v2',
339 |       'ml-2',
340 |       'promo-filter-apply',
341 |     ]);
342 |   });
343 | 
344 |   it('should handle dark mode conditional classes', () => {
345 |     const expression = `{ 
346 |       'bg-body-10': !darkModeService.isEnabled, 
347 |       'dark-mode-background': darkModeService.isEnabled 
348 |     }`;
349 |     const astWithSource = parseNgClassExpression(expression);
350 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
351 |       'bg-body-10',
352 |       'dark-mode-background',
353 |       'other-class',
354 |     ]);
355 | 
356 |     expect(result).toEqual(['bg-body-10', 'dark-mode-background']);
357 |   });
358 | 
359 |   it('should handle simple boolean-based ngClass', () => {
360 |     const expression = `{ 'offers-navigation-enable-v1': subNavigationV1Enabled }`;
361 |     const astWithSource = parseNgClassExpression(expression);
362 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
363 |       'offers-navigation-enable-v1',
364 |       'other-class',
365 |     ]);
366 | 
367 |     expect(result).toEqual(['offers-navigation-enable-v1']);
368 |   });
369 | 
370 |   it('should handle responsive class conditions', () => {
371 |     const expression = `{ 
372 |       'mobile-card-middle': isMobile,
373 |       'btn-sm': isSmallScreen,
374 |       'form-width-75': !isMobile 
375 |     }`;
376 |     const astWithSource = parseNgClassExpression(expression);
377 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
378 |       'mobile-card-middle',
379 |       'btn-sm',
380 |       'form-width-75',
381 |     ]);
382 | 
383 |     expect(result).toEqual(['mobile-card-middle', 'btn-sm', 'form-width-75']);
384 |   });
385 | 
386 |   it('should handle property-based class binding', () => {
387 |     const expression = `filterByProduct?.messages?.producticonclass`;
388 |     const astWithSource = parseNgClassExpression(expression);
389 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
390 |       'icon-class',
391 |       'ui-icon',
392 |     ]);
393 | 
394 |     expect(result).toEqual([]);
395 |   });
396 | 
397 |   it('should avoid false positives in complex comparison expressions', () => {
398 |     const expression = `{ 
399 |       'disabled': filtersByOffer?.count === 0,
400 |       'badge-counter': selectedFilterIndexes?.totalCount > 0,
401 |       'active': selectedFilters && selectedFilters.length > 0
402 |     }`;
403 |     const astWithSource = parseNgClassExpression(expression);
404 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
405 |       'disabled',
406 |       'badge-counter',
407 |       'active',
408 |       'count',
409 |       'selectedFilters',
410 |     ]);
411 | 
412 |     expect(result).toEqual(['disabled', 'badge-counter', 'active']);
413 |   });
414 | 
415 |   it('should handle mixed static and conditional classes', () => {
416 |     const expression = `[
417 |       'navbar', 
418 |       'navbar-expand-sm', 
419 |       condition ? 'sub-nav-wrapper' : '',
420 |       menuContainer?.class
421 |     ]`;
422 |     const astWithSource = parseNgClassExpression(expression);
423 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
424 |       'navbar',
425 |       'navbar-expand-sm',
426 |       'sub-nav-wrapper',
427 |       'other-class',
428 |     ]);
429 | 
430 |     expect(result).toEqual(['navbar', 'navbar-expand-sm', 'sub-nav-wrapper']);
431 |   });
432 | 
433 |   it('should handle the exact problematic pattern from the original issue', () => {
434 |     // The exact pattern that was causing false positives
435 |     const expression = `[
436 |       option?.logo?.toLowerCase(), 
437 |       option?.logo?.toLowerCase() == 'card' ? mergedCardLogoClass : '',
438 |       'base-class'
439 |     ]`;
440 |     const astWithSource = parseNgClassExpression(expression);
441 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
442 |       'card',
443 |       'base-class',
444 |       'other',
445 |     ]);
446 | 
447 |     expect(result).toEqual(['base-class']);
448 |   });
449 | 
450 |   it('should handle nested object with spaced class names', () => {
451 |     // Based on filter popup patterns
452 |     const expression = `{ 
453 |       'filter-product-icon ui-icon': true,
454 |       'ui-icon-size-lg': iconSize === 'large',
455 |       'status-pills transparent': hasTransparentStyle
456 |     }`;
457 |     const astWithSource = parseNgClassExpression(expression);
458 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
459 |       'filter-product-icon',
460 |       'ui-icon',
461 |       'ui-icon-size-lg',
462 |       'status-pills',
463 |       'transparent',
464 |       'large',
465 |     ]);
466 | 
467 |     expect(result).toEqual([
468 |       'filter-product-icon',
469 |       'ui-icon',
470 |       'ui-icon-size-lg',
471 |       'status-pills',
472 |       'transparent',
473 |     ]);
474 |   });
475 | });
476 | 
477 | describe('Real-world [class] binding patterns', () => {
478 |   // Helper function to extract AST from [class] expression
479 |   function parseClassExpression(expression: string): ASTWithSource {
480 |     const template = `<div [class]="${expression}"></div>`;
481 |     const result = parseTemplate(template, 'test.html');
482 |     const element = result.nodes[0] as TmplAstElement;
483 |     const classInput = element.inputs.find((input) => input.name === 'class');
484 |     return classInput?.value as ASTWithSource;
485 |   }
486 | 
487 |   it('should handle conditional class strings', () => {
488 |     const expression = `isActive ? 'nav-item active' : 'nav-item'`;
489 |     const astWithSource = parseClassExpression(expression);
490 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
491 |       'nav-item',
492 |       'active',
493 |       'inactive',
494 |     ]);
495 | 
496 |     expect(result).toEqual(['nav-item', 'active']);
497 |   });
498 | 
499 |   it('should handle complex ternary with comparison false positive potential', () => {
500 |     const expression = `userType === 'admin' ? 'admin-panel active' : userType === 'user' ? 'user-panel' : 'guest-panel'`;
501 |     const astWithSource = parseClassExpression(expression);
502 |     const result = extractClassNamesFromNgClassAST(astWithSource.ast, [
503 |       'admin',
504 |       'admin-panel',
505 |       'active',
506 |       'user',
507 |       'user-panel',
508 |       'guest-panel',
509 |     ]);
510 | 
511 |     expect(result).toEqual([
512 |       'admin-panel',
513 |       'active',
514 |       'user-panel',
515 |       'guest-panel',
516 |     ]);
517 |   });
518 | });
519 | 
520 | describe('Backward compatibility - ngClassesIncludeClassName', () => {
521 |   it('should work with object expressions', () => {
522 |     const expression = `{ 'btn': true, 'btn-primary': isActive }`;
523 |     expect(ngClassesIncludeClassName(expression, 'btn')).toBe(true);
524 |     expect(ngClassesIncludeClassName(expression, 'btn-primary')).toBe(true);
525 |     expect(ngClassesIncludeClassName(expression, 'btn-secondary')).toBe(false);
526 |   });
527 | 
528 |   it('should work with array expressions', () => {
529 |     const expression = `['btn', 'btn-primary', condition ? 'active' : '']`;
530 |     expect(ngClassesIncludeClassName(expression, 'btn')).toBe(true);
531 |     expect(ngClassesIncludeClassName(expression, 'btn-primary')).toBe(true);
532 |     expect(ngClassesIncludeClassName(expression, 'active')).toBe(true);
533 |     expect(ngClassesIncludeClassName(expression, 'inactive')).toBe(false);
534 |   });
535 | 
536 |   it('should work with string expressions', () => {
537 |     const expression = `'btn btn-primary active'`;
538 |     expect(ngClassesIncludeClassName(expression, 'btn')).toBe(true);
539 |     expect(ngClassesIncludeClassName(expression, 'btn-primary')).toBe(true);
540 |     expect(ngClassesIncludeClassName(expression, 'active')).toBe(true);
541 |     expect(ngClassesIncludeClassName(expression, 'inactive')).toBe(false);
542 |   });
543 | 
544 |   it('should handle basic string matching', () => {
545 |     const expression = `{ 'btn': option?.logo?.toLowerCase() === 'card', 'active': true }`;
546 |     expect(ngClassesIncludeClassName(expression, 'btn')).toBe(true);
547 |     expect(ngClassesIncludeClassName(expression, 'active')).toBe(true);
548 |   });
549 | 
550 |   it('should handle missing classes', () => {
551 |     const expression = `{ 'other': true }`;
552 |     expect(ngClassesIncludeClassName(expression, 'btn')).toBe(false);
553 |   });
554 | });
555 | 
```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/storybook-host-app/src/components/badge/badge.component.stories.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { generateStatusBadges } from '@design-system/shared-storybook-utils';
  2 | import { DemoIconComponent } from '@design-system/storybook-demo-cmp-lib';
  3 | import {
  4 |   DS_BADGE_SIZE_ARRAY,
  5 |   DS_BADGE_VARIANT_ARRAY,
  6 |   DsBadge,
  7 | } from '@frontend/ui/badge';
  8 | import { DsNotificationBubble } from '@frontend/ui/notification-bubble';
  9 | import {
 10 |   DsComplexityRatingComponent,
 11 |   getVariantInfo,
 12 | } from '@frontend/ui/utils';
 13 | import { Meta, StoryObj, moduleMetadata } from '@storybook/angular';
 14 | 
 15 | import { allThemes } from '../../modes';
 16 | 
 17 | type DsBadgeStoryType = DsBadge & { label: string };
 18 | 
 19 | const meta: Meta<DsBadgeStoryType> = {
 20 |   title: 'Components/Badge',
 21 |   component: DsBadge,
 22 |   parameters: {
 23 |     status: generateStatusBadges('UX-2308', ['stable']),
 24 |   },
 25 | 
 26 |   excludeStories: /.*Data$/,
 27 |   argTypes: {
 28 |     label: {
 29 |       type: 'string',
 30 |       table: { defaultValue: { summary: 'Label' } },
 31 |       control: 'text',
 32 |       description: 'The text of the badge',
 33 |     },
 34 |     size: {
 35 |       options: DS_BADGE_SIZE_ARRAY,
 36 |       table: { defaultValue: { summary: 'medium' }, category: 'Styling' },
 37 |       control: { type: 'select' },
 38 |       description: 'The size of the badge',
 39 |     },
 40 |     variant: {
 41 |       options: DS_BADGE_VARIANT_ARRAY,
 42 |       table: { defaultValue: { summary: 'primary' }, category: 'Styling' },
 43 |       control: { type: 'select' },
 44 |       description: 'The variant of the badge',
 45 |     },
 46 |     inverse: {
 47 |       type: 'boolean',
 48 |       table: { defaultValue: { summary: 'false' }, category: 'Styling' },
 49 |       control: { type: 'boolean' },
 50 |       description: 'The inverse state of the badge',
 51 |     },
 52 |     disabled: {
 53 |       type: 'boolean',
 54 |       table: {
 55 |         defaultValue: { summary: 'false' },
 56 |       },
 57 |       control: { type: 'boolean' },
 58 |       description: 'The disabled state of the badges',
 59 |     },
 60 |   },
 61 |   args: {
 62 |     label: 'Label',
 63 |     size: 'medium',
 64 |     variant: 'primary',
 65 |     disabled: false,
 66 |     inverse: false,
 67 |   },
 68 |   decorators: [
 69 |     moduleMetadata({ imports: [DemoIconComponent, DsNotificationBubble] }),
 70 |   ],
 71 | };
 72 | 
 73 | export default meta;
 74 | 
 75 | type Story = StoryObj<DsBadgeStoryType>;
 76 | 
 77 | export const Default: Story = {
 78 |   parameters: {
 79 |     name: 'Default',
 80 |     design: {
 81 |       name: 'Whitelabel',
 82 |       type: 'figma',
 83 |       url: 'https://www.figma.com/file/NgrOt8MGJhe0obKFBQgqdT/Component-Tokens-(POC)?type=design&node-id=16640-68740&&mode=design&t=fS1qO73SS8lGciLj-4',
 84 |     },
 85 |   },
 86 |   name: 'Default',
 87 |   args: {
 88 |     ...meta.args,
 89 |   },
 90 |   render: (badge) => ({
 91 |     template: `
 92 |         <ds-badge variant="${badge.variant}" size="${badge.size}" disabled="${badge.disabled}" [inverse]="${badge.inverse}">
 93 |             ${badge.label}
 94 |         </ds-badge>
 95 |         `,
 96 |   }),
 97 | };
 98 | 
 99 | export const WithIcon: Story = {
100 |   parameters: {
101 |     name: 'Default',
102 |     design: {
103 |       name: 'Whitelabel',
104 |       type: 'figma',
105 |       url: 'https://www.figma.com/file/NgrOt8MGJhe0obKFBQgqdT/Component-Tokens-(POC)?type=design&node-id=16640-68740&&mode=design&t=fS1qO73SS8lGciLj-4',
106 |     },
107 |   },
108 |   args: {
109 |     ...Default.args,
110 |   },
111 |   argTypes: {
112 |     ...Default.argTypes,
113 |     size: {
114 |       options: ['medium', 'xsmall'],
115 |     },
116 |   },
117 |   decorators: [moduleMetadata({ imports: [DsBadge] })],
118 |   render: (badge) => ({
119 |     template: `
120 |         <ds-badge variant="${badge.variant}" size="${badge.size}" disabled="${badge.disabled}" [inverse]="${badge.inverse}">
121 |             ${badge.label}
122 |             <ds-demo-icon slot="start"/>
123 |         </ds-badge>
124 |         `,
125 |   }),
126 | };
127 | 
128 | export const WithIconOnly: Story = {
129 |   parameters: {
130 |     name: 'Default',
131 |     design: {
132 |       name: 'Whitelabel',
133 |       type: 'figma',
134 |       url: 'https://www.figma.com/file/NgrOt8MGJhe0obKFBQgqdT/Component-Tokens-(POC)?type=design&node-id=16640-68740&&mode=design&t=fS1qO73SS8lGciLj-4',
135 |     },
136 |   },
137 |   args: {
138 |     ...Default.args,
139 |     label: '',
140 |   },
141 |   argTypes: {
142 |     ...Default.argTypes,
143 |     size: {
144 |       options: ['medium', 'xsmall'],
145 |     },
146 |   },
147 |   decorators: [moduleMetadata({ imports: [DsBadge] })],
148 |   render: (badge) => ({
149 |     template: `
150 |         <ds-badge variant="${badge.variant}" size="${badge.size}" disabled="${badge.disabled}" [inverse]="${badge.inverse}">
151 |             ${badge.label}
152 |             <ds-demo-icon slot="start"/>
153 |         </ds-badge>
154 |         `,
155 |   }),
156 | };
157 | 
158 | export const WithNotificationBubble: Story = {
159 |   parameters: {
160 |     name: 'Default',
161 |     design: {
162 |       name: 'Whitelabel',
163 |       type: 'figma',
164 |       url: 'https://www.figma.com/file/NgrOt8MGJhe0obKFBQgqdT/Component-Tokens-(POC)?type=design&node-id=16640-68740&&mode=design&t=fS1qO73SS8lGciLj-4',
165 |     },
166 |   },
167 |   args: {
168 |     ...Default.args,
169 |   },
170 |   argTypes: {
171 |     ...Default.argTypes,
172 |     size: {
173 |       options: ['medium'],
174 |     },
175 |   },
176 |   decorators: [moduleMetadata({ imports: [DsBadge] })],
177 |   render: (badge) => ({
178 |     template: `
179 |         <ds-badge variant="${badge.variant}" size="${badge.size}" disabled="${badge.disabled}" [inverse]="${badge.inverse}">
180 |             ${badge.label}
181 |               <ds-notification-bubble slot="start" variant="neutral" disabled="false" size="small" inverse="false">0</ds-notification-bubble>
182 |         </ds-badge>
183 |         `,
184 |   }),
185 | };
186 | 
187 | export const variantInfo = {
188 |   ...getVariantInfo(meta),
189 |   tags: ['docs-template'],
190 | };
191 | 
192 | export const ComplexityLevel: Story = {
193 |   tags: ['docs-template'],
194 | 
195 |   render: () => ({
196 |     moduleMetadata: {
197 |       imports: [DsComplexityRatingComponent],
198 |     },
199 |     template: `
200 |             <ds-complexity-rating 
201 |                 [totalVariants]="variantInfo.totalCombinations"
202 |                 [variantOptions]="variantInfo.variantOptions"
203 |                 [sizeOptions]="variantInfo.sizeOptions"
204 |             ></ds-complexity-rating>
205 |         `,
206 |     props: {
207 |       variantInfo,
208 |     },
209 |   }),
210 | };
211 | 
212 | export const WithSuccess: Story = {
213 |   parameters: {
214 |     name: 'Default',
215 |     design: {
216 |       name: 'Whitelabel',
217 |       type: 'figma',
218 |       url: 'https://www.figma.com/file/NgrOt8MGJhe0obKFBQgqdT/Component-Tokens-(POC)?type=design&node-id=16640-68740&&mode=design&t=fS1qO73SS8lGciLj-4',
219 |     },
220 |   },
221 |   args: {
222 |     ...Default.args,
223 |   },
224 | 
225 |   decorators: [moduleMetadata({})],
226 |   render: (badge) => ({
227 |     template: `
228 |         <ds-badge variant="${badge.variant}" size="${badge.size}" disabled="${badge.disabled}" [inverse]="${badge.inverse}">
229 |             ${badge.label}
230 |             <ds-demo-icon iconName="success" slot="end" />
231 |         </ds-badge>
232 |         `,
233 |   }),
234 | };
235 | 
236 | export const WithIconAndSuccess: Story = {
237 |   parameters: {
238 |     name: 'Default',
239 |     design: {
240 |       name: 'Whitelabel',
241 |       type: 'figma',
242 |       url: 'https://www.figma.com/file/NgrOt8MGJhe0obKFBQgqdT/Component-Tokens-(POC)?type=design&node-id=16640-68740&&mode=design&t=fS1qO73SS8lGciLj-4',
243 |     },
244 |   },
245 |   args: {
246 |     ...WithIcon.args,
247 |   },
248 | 
249 |   decorators: [moduleMetadata({})],
250 |   render: (badge) => ({
251 |     template: `
252 |         <ds-badge variant="${badge.variant}" size="${badge.size}" disabled="${badge.disabled}" [inverse]="${badge.inverse}">
253 |             ${badge.label}
254 |             <ds-demo-icon slot="start"/>
255 |             <ds-demo-icon iconName="success" slot="end" />
256 |         </ds-badge>
257 |         `,
258 |   }),
259 | };
260 | 
261 | export const LargeExamples: Story = {
262 |   tags: ['docs-template'],
263 |   render: (args) => ({
264 |     props: args,
265 |     template: `
266 |             <div style="display: grid; grid-template-columns: 1fr repeat(3, 1fr); grid-row-gap: 1em; grid-column-gap: 1em; text-align: left; align-items: center;">
267 |                 ${renderHeaderRow(
268 |                   'Primary',
269 |                   'Primary',
270 |                   'Primary Strong',
271 |                   'Primary Subtle',
272 |                 )}
273 |                 ${renderPrimaryRows('medium')}
274 |                 <div style="grid-column: 1 / -1;">
275 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
276 |                 </div>
277 |                 ${renderHeaderRow(
278 |                   'Secondary',
279 |                   'Secondary',
280 |                   'Secondary Strong',
281 |                   'Secondary Subtle',
282 |                 )}
283 |                 ${renderSecondaryRows('medium')}
284 |                 <div style="grid-column: 1 / -1;">
285 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
286 |                 </div>
287 |                 ${renderHeaderRow(
288 |                   'Green',
289 |                   'Green',
290 |                   'Green Strong',
291 |                   'Green Subtle',
292 |                 )}
293 |                 ${renderGreenRows('medium')}
294 |                 <div style="grid-column: 1 / -1;">
295 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
296 |                 </div>
297 |                 ${renderHeaderRow('Blue', 'Blue', 'Blue Strong', 'Blue Subtle')}
298 |                 ${renderBlueRows('medium')}
299 |                 <div style="grid-column: 1 / -1;">
300 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
301 |                 </div>
302 |                 ${renderHeaderRow('Red', 'Red', 'Red Strong', 'Red Subtle')}
303 |                 ${renderRedRows('medium')}
304 |                 <div style="grid-column: 1 / -1;">
305 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
306 |                 </div>
307 |                 ${renderHeaderRow(
308 |                   'Neutral',
309 |                   'Neutral',
310 |                   'Neutral Strong',
311 |                   'Neutral Subtle',
312 |                 )}
313 |                 ${renderNeutralRows('medium')}
314 |                 <div style="grid-column: 1 / -1;">
315 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
316 |                 </div>
317 |                 ${renderHeaderRow(
318 |                   'Purple',
319 |                   'Purple',
320 |                   'Purple Strong',
321 |                   'Purple Subtle',
322 |                 )}
323 |                 ${renderPurpleRows('medium')}
324 |                 <div style="grid-column: 1 / -1;">
325 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
326 |                 </div>
327 |                 ${renderHeaderRow(
328 |                   'Yellow',
329 |                   'Yellow',
330 |                   'Yellow Strong',
331 |                   'Yellow Subtle',
332 |                 )}
333 |                 ${renderYellowRows('medium')}
334 |                 <div style="grid-column: 1 / -1;">
335 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
336 |                 </div>
337 |                 ${renderHeaderRow(
338 |                   'Orange',
339 |                   'Orange',
340 |                   'Orange Strong',
341 |                   'Orange Subtle',
342 |                 )}
343 |                 ${renderOrangeRows('medium')}
344 |                 <div style="grid-column: 1 / -1;">
345 |                     <hr style="width: 100%; border: 1px solid #ddd; margin: 20px 0;">
346 |                 </div>
347 |             </div>
348 |         `,
349 |   }),
350 | };
351 | 
352 | function renderHeaderRow(title = '', col1 = '', col2 = '', col3 = '') {
353 |   return `
354 |         <div style="grid-column: 1 / span 1; text-align: left; margin-top: 20px;">
355 |             <strong>${title}</strong>
356 |         </div>
357 |         <div style="grid-column: 2 / span 1; text-align: left; margin-top: 20px;">
358 |             <strong>${col1}</strong>
359 |         </div>
360 |         <div style="grid-column: 3 / span 1; text-align: left; margin-top: 20px;">
361 |             <strong>${col2}</strong>
362 |         </div>
363 |         <div style="grid-column: 4 / span 1; text-align: left; margin-top: 20px;">
364 |             <strong>${col3}</strong>
365 |         </div>
366 |     `;
367 | }
368 | 
369 | function renderPrimaryRows(size: string) {
370 |   return `
371 |         ${renderRow('No Icon, No Success', size)}
372 |         ${renderRow('Icon', size, { showIcon: true })}
373 |         ${renderRow('Icon Only', size, { showIcon: true, showIconOnly: true })}
374 |         ${renderRow('Notification Bubble', size, {
375 |           showNotificationBubble: true,
376 |         })}
377 |         ${renderRow('Success', size, { showSuccess: true })}
378 |         ${renderRow('Icon + Success', size, {
379 |           showIcon: true,
380 |           showSuccess: true,
381 |         })}
382 |     `;
383 | }
384 | 
385 | function renderSecondaryRows(size: string) {
386 |   return `
387 |         ${renderRow('No Icon, No Success', size, {
388 |           variantPrefix: 'secondary',
389 |         })}
390 |         ${renderRow('Icon', size, {
391 |           showIcon: true,
392 |           variantPrefix: 'secondary',
393 |         })}
394 |         ${renderRow('Icon Only', size, {
395 |           showIcon: true,
396 |           showIconOnly: true,
397 |           variantPrefix: 'secondary',
398 |         })}
399 |         ${renderRow('Notification Bubble', size, {
400 |           showNotificationBubble: true,
401 |           variantPrefix: 'secondary',
402 |         })}
403 |         ${renderRow('Success', size, {
404 |           showSuccess: true,
405 |           variantPrefix: 'secondary',
406 |         })}
407 |         ${renderRow('Icon + Success', size, {
408 |           showIcon: true,
409 |           showSuccess: true,
410 |           variantPrefix: 'secondary',
411 |         })}
412 |     `;
413 | }
414 | 
415 | function renderGreenRows(size: string) {
416 |   return `
417 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'green' })}
418 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'green' })}
419 |         ${renderRow('Icon Only', size, {
420 |           showIcon: true,
421 |           showIconOnly: true,
422 |           variantPrefix: 'green',
423 |         })}
424 |         ${renderRow('Notification Bubble', size, {
425 |           showNotificationBubble: true,
426 |           variantPrefix: 'green',
427 |         })}
428 |         ${renderRow('Success', size, {
429 |           showSuccess: true,
430 |           variantPrefix: 'green',
431 |         })}
432 |         ${renderRow('Icon + Success', size, {
433 |           showIcon: true,
434 |           showSuccess: true,
435 |           variantPrefix: 'green',
436 |         })}
437 |     `;
438 | }
439 | 
440 | function renderBlueRows(size: string) {
441 |   return `
442 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'blue' })}
443 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'blue' })}
444 |         ${renderRow('Icon Only', size, {
445 |           showIcon: true,
446 |           showIconOnly: true,
447 |           variantPrefix: 'blue',
448 |         })}
449 |         ${renderRow('Notification Bubble', size, {
450 |           showNotificationBubble: true,
451 |           variantPrefix: 'blue',
452 |         })}
453 |         ${renderRow('Success', size, {
454 |           showSuccess: true,
455 |           variantPrefix: 'blue',
456 |         })}
457 |         ${renderRow('Icon + Success', size, {
458 |           showIcon: true,
459 |           showSuccess: true,
460 |           variantPrefix: 'blue',
461 |         })}
462 |     `;
463 | }
464 | 
465 | function renderRedRows(size: string) {
466 |   return `
467 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'red' })}
468 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'red' })}
469 |         ${renderRow('Icon Only', size, {
470 |           showIcon: true,
471 |           showIconOnly: true,
472 |           variantPrefix: 'red',
473 |         })}
474 |         ${renderRow('Notification Bubble', size, {
475 |           showNotificationBubble: true,
476 |           variantPrefix: 'red',
477 |         })}
478 |         ${renderRow('Success', size, {
479 |           showSuccess: true,
480 |           variantPrefix: 'red',
481 |         })}
482 |         ${renderRow('Icon + Success', size, {
483 |           showIcon: true,
484 |           showSuccess: true,
485 |           variantPrefix: 'red',
486 |         })}
487 |     `;
488 | }
489 | 
490 | function renderNeutralRows(size: string) {
491 |   return `
492 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'neutral' })}
493 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'neutral' })}
494 |         ${renderRow('Icon Only', size, {
495 |           showIcon: true,
496 |           showIconOnly: true,
497 |           variantPrefix: 'neutral',
498 |         })}
499 |         ${renderRow('Notification Bubble', size, {
500 |           showNotificationBubble: true,
501 |           variantPrefix: 'neutral',
502 |         })}
503 |         ${renderRow('Success', size, {
504 |           showSuccess: true,
505 |           variantPrefix: 'neutral',
506 |         })}
507 |         ${renderRow('Icon + Success', size, {
508 |           showIcon: true,
509 |           showSuccess: true,
510 |           variantPrefix: 'neutral',
511 |         })}
512 |     `;
513 | }
514 | 
515 | function renderPurpleRows(size: string) {
516 |   return `
517 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'purple' })}
518 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'purple' })}
519 |         ${renderRow('Icon Only', size, {
520 |           showIcon: true,
521 |           showIconOnly: true,
522 |           variantPrefix: 'purple',
523 |         })}
524 |         ${renderRow('Notification Bubble', size, {
525 |           showNotificationBubble: true,
526 |           variantPrefix: 'purple',
527 |         })}
528 |         ${renderRow('Success', size, {
529 |           showSuccess: true,
530 |           variantPrefix: 'purple',
531 |         })}
532 |         ${renderRow('Icon + Success', size, {
533 |           showIcon: true,
534 |           showSuccess: true,
535 |           variantPrefix: 'purple',
536 |         })}
537 |     `;
538 | }
539 | 
540 | function renderYellowRows(size: string) {
541 |   return `
542 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'yellow' })}
543 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'yellow' })}
544 |         ${renderRow('Icon Only', size, {
545 |           showIcon: true,
546 |           showIconOnly: true,
547 |           variantPrefix: 'yellow',
548 |         })}
549 |         ${renderRow('Notification Bubble', size, {
550 |           showNotificationBubble: true,
551 |           variantPrefix: 'yellow',
552 |         })}
553 |         ${renderRow('Success', size, {
554 |           showSuccess: true,
555 |           variantPrefix: 'yellow',
556 |         })}
557 |         ${renderRow('Icon + Success', size, {
558 |           showIcon: true,
559 |           showSuccess: true,
560 |           variantPrefix: 'yellow',
561 |         })}
562 |     `;
563 | }
564 | 
565 | function renderOrangeRows(size: string) {
566 |   return `
567 |         ${renderRow('No Icon, No Success', size, { variantPrefix: 'orange' })}
568 |         ${renderRow('Icon', size, { showIcon: true, variantPrefix: 'orange' })}
569 |         ${renderRow('Icon Only', size, {
570 |           showIcon: true,
571 |           showIconOnly: true,
572 |           variantPrefix: 'orange',
573 |         })}
574 |         ${renderRow('Notification Bubble', size, {
575 |           showNotificationBubble: true,
576 |           variantPrefix: 'orange',
577 |         })}
578 |         ${renderRow('Success', size, {
579 |           showSuccess: true,
580 |           variantPrefix: 'orange',
581 |         })}
582 |         ${renderRow('Icon + Success', size, {
583 |           showIcon: true,
584 |           showSuccess: true,
585 |           variantPrefix: 'orange',
586 |         })}
587 |     `;
588 | }
589 | 
590 | function renderRow(
591 |   name: string,
592 |   size: string,
593 |   {
594 |     showSuccess = false,
595 |     showIcon = false,
596 |     showIconOnly = false,
597 |     showNotificationBubble = false,
598 |     variantPrefix = 'primary',
599 |   } = {},
600 | ) {
601 |   return `
602 |         <span style="grid-column: 1 / span 1; align-self: center;">${name}</span>
603 |         ${renderBadge(
604 |           `${variantPrefix}`,
605 |           size,
606 |           showIcon,
607 |           showIconOnly,
608 |           showNotificationBubble,
609 |           showSuccess,
610 |         )}
611 |         ${renderBadge(
612 |           `${variantPrefix}-strong`,
613 |           size,
614 |           showIcon,
615 |           showIconOnly,
616 |           showNotificationBubble,
617 |           showSuccess,
618 |         )}
619 |         ${renderBadge(
620 |           `${variantPrefix}-subtle`,
621 |           size,
622 |           showIcon,
623 |           showIconOnly,
624 |           showNotificationBubble,
625 |           showSuccess,
626 |         )}
627 |     `;
628 | }
629 | 
630 | function renderBadge(
631 |   variant: string,
632 |   size: string,
633 |   showIcon: boolean,
634 |   showIconOnly: boolean,
635 |   showNotificationBubble: boolean,
636 |   showSuccess: boolean,
637 | ) {
638 |   return `
639 |         <div style="grid-column: span 1;">
640 |             <ds-badge variant="${variant}" size="${size}">
641 |                 ${showIconOnly ? '' : 'Label'}
642 |                 ${showIcon ? '<ds-demo-icon slot="start"/>' : ''}
643 |                 ${
644 |                   showNotificationBubble
645 |                     ? '<ds-notification-bubble slot="start" variant="neutral" disabled="false" size="small" inverse="false">0</ds-notification-bubble>'
646 |                     : ''
647 |                 }
648 |                 ${
649 |                   showSuccess
650 |                     ? '<ds-demo-icon iconName="success" slot="end"/>'
651 |                     : ''
652 |                 }
653 |             </ds-badge>
654 |         </div>
655 |     `;
656 | }
657 | export const ChromaticTestStory: Story = {
658 |   tags: ['docs-template'],
659 |   parameters: {
660 |     chromatic: {
661 |       modes: allThemes,
662 |       disableSnapshot: false,
663 |     },
664 |   },
665 |   render: (args) => ({
666 |     props: args,
667 |     template: `
668 |             <div style="display: grid; grid-template-columns: repeat(7, 1fr); grid-row-gap: 1em; grid-column-gap: 1em; align-items: center; justify-items: center;">
669 |                 
670 |             
671 |                 ${renderHeaderRow()}
672 |                 
673 |                 ${renderRow('Xsmall', 'xsmall')}
674 |                 
675 |                 <div style="grid-column: span 7"></div>
676 |                 ${renderRow('Medium', 'medium')}
677 |                 ${renderRow('Medium, Icon', 'medium', { showIcon: true })}
678 |                 ${renderRow('Medium, IconOnly', 'medium', {
679 |                   showIcon: true,
680 |                   showIconOnly: true,
681 |                 })}
682 |                 ${renderRow('Medium, NotificationBubble', 'medium', {
683 |                   showNotificationBubble: true,
684 |                 })}
685 |                 ${renderRow('Medium, Success', 'medium', { showSuccess: true })}
686 |                 ${renderRow('Medium, Icon + Success', 'medium', {
687 |                   showIcon: true,
688 |                   showSuccess: true,
689 |                 })}
690 |                 
691 |                 <div style="grid-column: span 7"></div>
692 |                 ${renderRow('Large', 'medium')}
693 |                 ${renderRow('Large, Icon', 'medium', { showIcon: true })}
694 |                 ${renderRow('Large, IconOnly', 'medium', {
695 |                   showIcon: true,
696 |                   showIconOnly: true,
697 |                 })}
698 |                 ${renderRow('Large, NotificationBubble', 'medium', {
699 |                   showNotificationBubble: true,
700 |                 })}
701 |                 ${renderRow('Large, Success', 'medium', { showSuccess: true })}
702 |                 ${renderRow('Large, Icon + Success', 'medium', {
703 |                   showIcon: true,
704 |                   showSuccess: true,
705 |                 })}
706 |             </div>
707 |         `,
708 |   }),
709 | };
710 | 
```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/docs/examples/report.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Code PushUp Report
  2 | 
  3 | | 🏷 Category                                       | ⭐ Score  | 🛡 Audits |
  4 | | :------------------------------------------------ | :-------: | :-------: |
  5 | | [Design System Coverage](#design-system-coverage) | 🔴 **38** |    13     |
  6 | 
  7 | ## 🏷 Categories
  8 | 
  9 | ### Design System Coverage
 10 | 
 11 | Usage of design system components
 12 | 
 13 | 🔴 Score: **38**
 14 | 
 15 | - 🟥 [Usage coverage for DSButton component](#usage-coverage-for-dsbutton-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **7 classes found**
 16 | - 🟥 [Usage coverage for DSAlert component](#usage-coverage-for-dsalert-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **6 classes found**
 17 | - 🟥 [Usage coverage for DSTooltip component](#usage-coverage-for-dstooltip-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **5 classes found**
 18 | - 🟥 [Usage coverage for DSBreadcrumb component](#usage-coverage-for-dsbreadcrumb-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **4 classes found**
 19 | - 🟥 [Usage coverage for DSDropdown component](#usage-coverage-for-dsdropdown-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **4 classes found**
 20 | - 🟥 [Usage coverage for DSModal component](#usage-coverage-for-dsmodal-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **4 classes found**
 21 | - 🟥 [Usage coverage for DSProgressBar component](#usage-coverage-for-dsprogressbar-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **4 classes found**
 22 | - 🟥 [Usage coverage for DSInput component](#usage-coverage-for-dsinput-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **1 class found**
 23 | - 🟩 [Usage coverage for DSAccordion component](#usage-coverage-for-dsaccordion-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **0 classes found**
 24 | - 🟩 [Usage coverage for DSCard component](#usage-coverage-for-dscard-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **0 classes found**
 25 | - 🟩 [Usage coverage for DSNavbar component](#usage-coverage-for-dsnavbar-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **0 classes found**
 26 | - 🟩 [Usage coverage for DSSlider component](#usage-coverage-for-dsslider-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **0 classes found**
 27 | - 🟩 [Usage coverage for DSTabsModule component](#usage-coverage-for-dstabsmodule-component-angular-design-system-coverage) (_Angular Design System Coverage_) - **0 classes found**
 28 | 
 29 | ## 🛡️ Audits
 30 | 
 31 | ### Usage coverage for DSButton component (Angular Design System Coverage)
 32 | 
 33 | <details>
 34 | <summary>🟥 <b>7 classes found</b> (score: 0)</summary>
 35 | 
 36 | #### Issues
 37 | 
 38 | |  Severity  | Message                                                                                                                                                                                                                                                                         | Source file                                                                                                                                                                                                                  | Line(s) |
 39 | | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
 40 | | 🚨 _error_ | ✏️🔲 Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn</code>. Use <code>DSButton</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>.         | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts)         |    6    |
 41 | | 🚨 _error_ | ✏️🔲 Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn-primary</code>. Use <code>DSButton</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts)         |    6    |
 42 | | 🚨 _error_ | ✏️🔲 Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn</code>. Use <code>DSButton</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>.         | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |   10    |
 43 | | 🚨 _error_ | ✏️🔲 Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn-primary</code>. Use <code>DSButton</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |   10    |
 44 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>btn</code> is deprecated. Use <code>DSButton</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>.                                        | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  7-14   |
 45 | | 🚨 _error_ | 🔗🔲 Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn</code>. Use <code>DSButton</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>.         | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |    6    |
 46 | | 🚨 _error_ | 🔗🔲 Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn-primary</code>. Use <code>DSButton</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-button--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |    6    |
 47 | 
 48 | </details>
 49 | 
 50 | Coverage audit for DSButton component. Matching classes: btn, btn-primary, legacy-button
 51 | 
 52 | ### Usage coverage for DSAlert component (Angular Design System Coverage)
 53 | 
 54 | <details>
 55 | <summary>🟥 <b>6 classes found</b> (score: 0)</summary>
 56 | 
 57 | #### Issues
 58 | 
 59 | |  Severity  | Message                                                                                                                                                                                                                                                              | Source file                                                                                                                                                                                                                  | Line(s) |
 60 | | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
 61 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-alert--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts) |    6    |
 62 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-alert--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert.component.ts)                             |    5    |
 63 | | 🚨 _error_ | ✏️🎨 ️ The selector's class <code>alert</code> is deprecated. Use <code>DSAlert</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-alert--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert.component.ts)                             |  7-10   |
 64 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-alert--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |   46    |
 65 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>alert</code> is deprecated. Use <code>DSAlert</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-alert--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  43-47  |
 66 | | 🚨 _error_ | 🔗🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-alert--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |   22    |
 67 | 
 68 | </details>
 69 | 
 70 | Coverage audit for DSAlert component. Matching classes: alert, notification, legacy-alert
 71 | 
 72 | ### Usage coverage for DSTooltip component (Angular Design System Coverage)
 73 | 
 74 | <details>
 75 | <summary>🟥 <b>5 classes found</b> (score: 0)</summary>
 76 | 
 77 | #### Issues
 78 | 
 79 | |  Severity  | Message                                                                                                                                                                                                                                                                    | Source file                                                                                                                                                                                                                  | Line(s) |
 80 | | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
 81 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>tooltip</code>. Use <code>DSTooltip</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-tooltip--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts) |    8    |
 82 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>tooltip</code>. Use <code>DSTooltip</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-tooltip--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |   52    |
 83 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>tooltip</code> is deprecated. Use <code>DSTooltip</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-tooltip--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  57-61  |
 84 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>tooltip</code> is deprecated. Use <code>DSTooltip</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-tooltip--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  63-73  |
 85 | | 🚨 _error_ | 🔗🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>tooltip</code>. Use <code>DSTooltip</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-tooltip--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |   31    |
 86 | 
 87 | </details>
 88 | 
 89 | Coverage audit for DSTooltip component. Matching classes: tooltip, legacy-tooltip, info-bubble
 90 | 
 91 | ### Usage coverage for DSBreadcrumb component (Angular Design System Coverage)
 92 | 
 93 | <details>
 94 | <summary>🟥 <b>4 classes found</b> (score: 0)</summary>
 95 | 
 96 | #### Issues
 97 | 
 98 | |  Severity  | Message                                                                                                                                                                                                                                                                             | Source file                                                                                                                                                                                                                  | Line(s) |
 99 | | :--------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
100 | | 🚨 _error_ | ✏️🔲 Element <code>nav</code> in attribute <code>class</code> uses deprecated class <code>breadcrumb</code>. Use <code>DSBreadcrumb</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |  62-64  |
101 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>breadcrumb</code> is deprecated. Use <code>DSBreadcrumb</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  76-79  |
102 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>breadcrumb</code> is deprecated. Use <code>DSBreadcrumb</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  81-84  |
103 | | 🚨 _error_ | 🔗🔲 Element <code>nav</code> in attribute <code>class</code> uses deprecated class <code>breadcrumb</code>. Use <code>DSBreadcrumb</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |  34-36  |
104 | 
105 | </details>
106 | 
107 | Coverage audit for DSBreadcrumb component. Matching classes: breadcrumb, legacy-breadcrumb, nav-breadcrumb
108 | 
109 | ### Usage coverage for DSDropdown component (Angular Design System Coverage)
110 | 
111 | <details>
112 | <summary>🟥 <b>4 classes found</b> (score: 0)</summary>
113 | 
114 | #### Issues
115 | 
116 | |  Severity  | Message                                                                                                                                                                                                                                                                          | Source file                                                                                                                                                                                                                  | Line(s) |
117 | | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
118 | | 🚨 _error_ | ✏️🔲 Element <code>select</code> in attribute <code>class</code> uses deprecated class <code>dropdown</code>. Use <code>DSDropdown</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-dropdown--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts)         |  7-10   |
119 | | 🚨 _error_ | ✏️🔲 Element <code>select</code> in attribute <code>class</code> uses deprecated class <code>dropdown</code>. Use <code>DSDropdown</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-dropdown--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |  37-40  |
120 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>dropdown</code> is deprecated. Use <code>DSDropdown</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-dropdown--overview" target="_blank">Learn more</a>.                                | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  50-54  |
121 | | 🚨 _error_ | 🔗🔲 Element <code>select</code> in attribute <code>class</code> uses deprecated class <code>dropdown</code>. Use <code>DSDropdown</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-dropdown--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |  25-28  |
122 | 
123 | </details>
124 | 
125 | Coverage audit for DSDropdown component. Matching classes: dropdown, legacy-dropdown, custom-dropdown
126 | 
127 | ### Usage coverage for DSModal component (Angular Design System Coverage)
128 | 
129 | <details>
130 | <summary>🟥 <b>4 classes found</b> (score: 0)</summary>
131 | 
132 | #### Issues
133 | 
134 | |  Severity  | Message                                                                                                                                                                                                                                                              | Source file                                                                                                                                                                                                                  | Line(s) |
135 | | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
136 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>modal</code>. Use <code>DSModal</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-modal--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |  18-23  |
137 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>modal</code>. Use <code>DSModal</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-modal--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-modal-progress.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-modal-progress.component.ts)           |  6-11   |
138 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>modal</code> is deprecated. Use <code>DSModal</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-modal--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  17-25  |
139 | | 🚨 _error_ | 🔗🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>modal</code>. Use <code>DSModal</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-modal--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |  9-14   |
140 | 
141 | </details>
142 | 
143 | Coverage audit for DSModal component. Matching classes: modal, popup, legacy-dialog
144 | 
145 | ### Usage coverage for DSProgressBar component (Angular Design System Coverage)
146 | 
147 | <details>
148 | <summary>🟥 <b>4 classes found</b> (score: 0)</summary>
149 | 
150 | #### Issues
151 | 
152 | |  Severity  | Message                                                                                                                                                                                                                                                                                 | Source file                                                                                                                                                                                                                  | Line(s) |
153 | | :--------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
154 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>progress-bar</code>. Use <code>DSProgressBar</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-progressbar--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts)                             |  29-31  |
155 | | 🚨 _error_ | ✏️🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>progress-bar</code>. Use <code>DSProgressBar</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-progressbar--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-modal-progress.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-modal-progress.component.ts)           |  13-15  |
156 | | 🚨 _error_ | 🔗🎨 ️ The selector's class <code>progress-bar</code> is deprecated. Use <code>DSProgressBar</code> and delete the styles. <a href="https://storybook.company.com/latest/?path=/docs/components-progressbar--overview" target="_blank">Learn more</a>.                             | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css)   |  32-35  |
157 | | 🚨 _error_ | 🔗🔲 Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>progress-bar</code>. Use <code>DSProgressBar</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-progressbar--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html) |  17-19  |
158 | 
159 | </details>
160 | 
161 | Coverage audit for DSProgressBar component. Matching classes: progress-bar, loading-bar, legacy-progress
162 | 
163 | ### Usage coverage for DSInput component (Angular Design System Coverage)
164 | 
165 | <details>
166 | <summary>🟥 <b>1 class found</b> (score: 0)</summary>
167 | 
168 | #### Issues
169 | 
170 | |  Severity  | Message                                                                                                                                                                                                                                                                       | Source file                                                                                                                                                                                                                  | Line(s) |
171 | | :--------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----: |
172 | | 🚨 _error_ | ✏️🔲 Element <code>input</code> in attribute <code>class</code> uses deprecated class <code>form-control</code>. Use <code>DSInput</code> instead. <a href="https://storybook.company.com/latest/?path=/docs/components-input--overview" target="_blank">Learn more</a>. | [`plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts`](../../../../plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts) |   10    |
173 | 
174 | </details>
175 | 
176 | Coverage audit for DSInput component. Matching classes: input, form-control, legacy-input
177 | 
178 | ### Usage coverage for DSAccordion component (Angular Design System Coverage)
179 | 
180 | 🟩 **0 classes found** (score: 100)
181 | 
182 | Coverage audit for DSAccordion component. Matching classes: accordion, collapse-panel, legacy-accordion
183 | 
184 | ### Usage coverage for DSCard component (Angular Design System Coverage)
185 | 
186 | 🟩 **0 classes found** (score: 100)
187 | 
188 | Coverage audit for DSCard component. Matching classes: card, legacy-card, custom-card
189 | 
190 | ### Usage coverage for DSNavbar component (Angular Design System Coverage)
191 | 
192 | 🟩 **0 classes found** (score: 100)
193 | 
194 | Coverage audit for DSNavbar component. Matching classes: navbar, navigation, legacy-navbar
195 | 
196 | ### Usage coverage for DSSlider component (Angular Design System Coverage)
197 | 
198 | 🟩 **0 classes found** (score: 100)
199 | 
200 | Coverage audit for DSSlider component. Matching classes: slider, range-slider, legacy-slider
201 | 
202 | ### Usage coverage for DSTabsModule component (Angular Design System Coverage)
203 | 
204 | 🟩 **0 classes found** (score: 100)
205 | 
206 | Coverage audit for DSTabsModule component. Matching classes: ms-tab-bar, legacy-tabs, custom-tabs
207 | 
208 | ## About
209 | 
210 | Report was created by [Code PushUp](https://github.com/code-pushup/cli#readme) on Mon, Feb 10, 2025, 11:48 PM GMT+1.
211 | 
212 | | Plugin                         | Audits | Version | Duration |
213 | | :----------------------------- | :----: | :-----: | -------: |
214 | | Angular Design System Coverage |   13   |         |   366 ms |
215 | 
216 | | Commit                                         | Version  | Duration | Plugins | Categories | Audits |
217 | | :--------------------------------------------- | :------: | -------: | :-----: | :--------: | :----: |
218 | | wip (523fdf3354f4fdb952ab324ac92f7e0f3cd61957) | `0.57.0` |   418 ms |    1    |     1      |   13   |
219 | 
220 | ---
221 | 
222 | Made with ❤ by [Code PushUp](https://github.com/code-pushup/cli#readme)
223 | 
```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/docs/examples/report.json:
--------------------------------------------------------------------------------

```json
  1 | {
  2 |   "commit": {
  3 |     "hash": "523fdf3354f4fdb952ab324ac92f7e0f3cd61957",
  4 |     "message": "wip",
  5 |     "date": "2025-02-10T22:11:27.000Z",
  6 |     "author": "Michael"
  7 |   },
  8 |   "packageName": "@push-based/core",
  9 |   "version": "0.57.0",
 10 |   "date": "2025-02-10T22:48:50.259Z",
 11 |   "duration": 418,
 12 |   "categories": [
 13 |     {
 14 |       "slug": "design-system-coverage",
 15 |       "refs": [
 16 |         {
 17 |           "slug": "coverage-dsbutton",
 18 |           "weight": 1,
 19 |           "type": "audit",
 20 |           "plugin": "ds-component-coverage"
 21 |         },
 22 |         {
 23 |           "slug": "coverage-dstabsmodule",
 24 |           "weight": 1,
 25 |           "type": "audit",
 26 |           "plugin": "ds-component-coverage"
 27 |         },
 28 |         {
 29 |           "slug": "coverage-dscard",
 30 |           "weight": 1,
 31 |           "type": "audit",
 32 |           "plugin": "ds-component-coverage"
 33 |         },
 34 |         {
 35 |           "slug": "coverage-dsmodal",
 36 |           "weight": 1,
 37 |           "type": "audit",
 38 |           "plugin": "ds-component-coverage"
 39 |         },
 40 |         {
 41 |           "slug": "coverage-dsinput",
 42 |           "weight": 1,
 43 |           "type": "audit",
 44 |           "plugin": "ds-component-coverage"
 45 |         },
 46 |         {
 47 |           "slug": "coverage-dsdropdown",
 48 |           "weight": 1,
 49 |           "type": "audit",
 50 |           "plugin": "ds-component-coverage"
 51 |         },
 52 |         {
 53 |           "slug": "coverage-dsaccordion",
 54 |           "weight": 1,
 55 |           "type": "audit",
 56 |           "plugin": "ds-component-coverage"
 57 |         },
 58 |         {
 59 |           "slug": "coverage-dsalert",
 60 |           "weight": 1,
 61 |           "type": "audit",
 62 |           "plugin": "ds-component-coverage"
 63 |         },
 64 |         {
 65 |           "slug": "coverage-dstooltip",
 66 |           "weight": 1,
 67 |           "type": "audit",
 68 |           "plugin": "ds-component-coverage"
 69 |         },
 70 |         {
 71 |           "slug": "coverage-dsbreadcrumb",
 72 |           "weight": 1,
 73 |           "type": "audit",
 74 |           "plugin": "ds-component-coverage"
 75 |         },
 76 |         {
 77 |           "slug": "coverage-dsprogressbar",
 78 |           "weight": 1,
 79 |           "type": "audit",
 80 |           "plugin": "ds-component-coverage"
 81 |         },
 82 |         {
 83 |           "slug": "coverage-dsslider",
 84 |           "weight": 1,
 85 |           "type": "audit",
 86 |           "plugin": "ds-component-coverage"
 87 |         },
 88 |         {
 89 |           "slug": "coverage-dsnavbar",
 90 |           "weight": 1,
 91 |           "type": "audit",
 92 |           "plugin": "ds-component-coverage"
 93 |         }
 94 |       ],
 95 |       "title": "Design System Coverage",
 96 |       "description": "Usage of design system components"
 97 |     }
 98 |   ],
 99 |   "plugins": [
100 |     {
101 |       "title": "Angular Design System Coverage",
102 |       "slug": "ds-component-coverage",
103 |       "icon": "angular",
104 |       "date": "2025-02-10T22:48:50.286Z",
105 |       "duration": 366,
106 |       "audits": [
107 |         {
108 |           "slug": "coverage-dsbutton",
109 |           "displayValue": "7 classes found",
110 |           "value": 7,
111 |           "score": 0,
112 |           "details": {
113 |             "issues": [
114 |               {
115 |                 "message": "✏️🔲  Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn</code>. Use <code>DSButton</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
116 |                 "severity": "error",
117 |                 "source": {
118 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
119 |                   "position": {
120 |                     "startLine": 10,
121 |                     "startColumn": 4,
122 |                     "endLine": 10,
123 |                     "endColumn": 55
124 |                   }
125 |                 }
126 |               },
127 |               {
128 |                 "message": "✏️🔲  Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn-primary</code>. Use <code>DSButton</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
129 |                 "severity": "error",
130 |                 "source": {
131 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
132 |                   "position": {
133 |                     "startLine": 10,
134 |                     "startColumn": 4,
135 |                     "endLine": 10,
136 |                     "endColumn": 55
137 |                   }
138 |                 }
139 |               },
140 |               {
141 |                 "message": "✏️🔲  Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn</code>. Use <code>DSButton</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
142 |                 "severity": "error",
143 |                 "source": {
144 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts",
145 |                   "position": {
146 |                     "startLine": 6,
147 |                     "startColumn": 4,
148 |                     "endLine": 6,
149 |                     "endColumn": 53
150 |                   }
151 |                 }
152 |               },
153 |               {
154 |                 "message": "✏️🔲  Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn-primary</code>. Use <code>DSButton</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
155 |                 "severity": "error",
156 |                 "source": {
157 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts",
158 |                   "position": {
159 |                     "startLine": 6,
160 |                     "startColumn": 4,
161 |                     "endLine": 6,
162 |                     "endColumn": 53
163 |                   }
164 |                 }
165 |               },
166 |               {
167 |                 "message": "🔗🔲  Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn</code>. Use <code>DSButton</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
168 |                 "severity": "error",
169 |                 "source": {
170 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
171 |                   "position": {
172 |                     "startLine": 6,
173 |                     "endLine": 6,
174 |                     "endColumn": 54
175 |                   }
176 |                 }
177 |               },
178 |               {
179 |                 "message": "🔗🔲  Element <code>button</code> in attribute <code>class</code> uses deprecated class <code>btn-primary</code>. Use <code>DSButton</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
180 |                 "severity": "error",
181 |                 "source": {
182 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
183 |                   "position": {
184 |                     "startLine": 6,
185 |                     "endLine": 6,
186 |                     "endColumn": 54
187 |                   }
188 |                 }
189 |               },
190 |               {
191 |                 "message": "🔗🎨 ️ The selector's class <code>btn</code> is deprecated. Use <code>DSButton</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-button--overview\" target=\"_blank\">Learn more</a>.",
192 |                 "severity": "error",
193 |                 "source": {
194 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
195 |                   "position": {
196 |                     "startLine": 7,
197 |                     "startColumn": 1,
198 |                     "endLine": 14,
199 |                     "endColumn": 1
200 |                   }
201 |                 }
202 |               }
203 |             ]
204 |           },
205 |           "title": "Usage coverage for DSButton component",
206 |           "description": "Coverage audit for DSButton component. Matching classes: btn, btn-primary, legacy-button"
207 |         },
208 |         {
209 |           "slug": "coverage-dstabsmodule",
210 |           "displayValue": "0 classes found",
211 |           "value": 0,
212 |           "score": 1,
213 |           "details": {
214 |             "issues": []
215 |           },
216 |           "title": "Usage coverage for DSTabsModule component",
217 |           "description": "Coverage audit for DSTabsModule component. Matching classes: ms-tab-bar, legacy-tabs, custom-tabs"
218 |         },
219 |         {
220 |           "slug": "coverage-dscard",
221 |           "displayValue": "0 classes found",
222 |           "value": 0,
223 |           "score": 1,
224 |           "details": {
225 |             "issues": []
226 |           },
227 |           "title": "Usage coverage for DSCard component",
228 |           "description": "Coverage audit for DSCard component. Matching classes: card, legacy-card, custom-card"
229 |         },
230 |         {
231 |           "slug": "coverage-dsmodal",
232 |           "displayValue": "4 classes found",
233 |           "value": 4,
234 |           "score": 0,
235 |           "details": {
236 |             "issues": [
237 |               {
238 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>modal</code>. Use <code>DSModal</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-modal--overview\" target=\"_blank\">Learn more</a>.",
239 |                 "severity": "error",
240 |                 "source": {
241 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-modal-progress.component.ts",
242 |                   "position": {
243 |                     "startLine": 6,
244 |                     "startColumn": 4,
245 |                     "endLine": 11,
246 |                     "endColumn": 10
247 |                   }
248 |                 }
249 |               },
250 |               {
251 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>modal</code>. Use <code>DSModal</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-modal--overview\" target=\"_blank\">Learn more</a>.",
252 |                 "severity": "error",
253 |                 "source": {
254 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
255 |                   "position": {
256 |                     "startLine": 18,
257 |                     "startColumn": 4,
258 |                     "endLine": 23,
259 |                     "endColumn": 10
260 |                   }
261 |                 }
262 |               },
263 |               {
264 |                 "message": "🔗🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>modal</code>. Use <code>DSModal</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-modal--overview\" target=\"_blank\">Learn more</a>.",
265 |                 "severity": "error",
266 |                 "source": {
267 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
268 |                   "position": {
269 |                     "startLine": 9,
270 |                     "endLine": 14,
271 |                     "endColumn": 6
272 |                   }
273 |                 }
274 |               },
275 |               {
276 |                 "message": "🔗🎨 ️ The selector's class <code>modal</code> is deprecated. Use <code>DSModal</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-modal--overview\" target=\"_blank\">Learn more</a>.",
277 |                 "severity": "error",
278 |                 "source": {
279 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
280 |                   "position": {
281 |                     "startLine": 17,
282 |                     "startColumn": 1,
283 |                     "endLine": 25,
284 |                     "endColumn": 1
285 |                   }
286 |                 }
287 |               }
288 |             ]
289 |           },
290 |           "title": "Usage coverage for DSModal component",
291 |           "description": "Coverage audit for DSModal component. Matching classes: modal, popup, legacy-dialog"
292 |         },
293 |         {
294 |           "slug": "coverage-dsinput",
295 |           "displayValue": "1 class found",
296 |           "value": 1,
297 |           "score": 0,
298 |           "details": {
299 |             "issues": [
300 |               {
301 |                 "message": "✏️🔲  Element <code>input</code> in attribute <code>class</code> uses deprecated class <code>form-control</code>. Use <code>DSInput</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-input--overview\" target=\"_blank\">Learn more</a>.",
302 |                 "severity": "error",
303 |                 "source": {
304 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts",
305 |                   "position": {
306 |                     "startLine": 10,
307 |                     "startColumn": 4,
308 |                     "endLine": 10,
309 |                     "endColumn": 64
310 |                   }
311 |                 }
312 |               }
313 |             ]
314 |           },
315 |           "title": "Usage coverage for DSInput component",
316 |           "description": "Coverage audit for DSInput component. Matching classes: input, form-control, legacy-input"
317 |         },
318 |         {
319 |           "slug": "coverage-dsdropdown",
320 |           "displayValue": "4 classes found",
321 |           "value": 4,
322 |           "score": 0,
323 |           "details": {
324 |             "issues": [
325 |               {
326 |                 "message": "✏️🔲  Element <code>select</code> in attribute <code>class</code> uses deprecated class <code>dropdown</code>. Use <code>DSDropdown</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-dropdown--overview\" target=\"_blank\">Learn more</a>.",
327 |                 "severity": "error",
328 |                 "source": {
329 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
330 |                   "position": {
331 |                     "startLine": 37,
332 |                     "startColumn": 4,
333 |                     "endLine": 40,
334 |                     "endColumn": 13
335 |                   }
336 |                 }
337 |               },
338 |               {
339 |                 "message": "✏️🔲  Element <code>select</code> in attribute <code>class</code> uses deprecated class <code>dropdown</code>. Use <code>DSDropdown</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-dropdown--overview\" target=\"_blank\">Learn more</a>.",
340 |                 "severity": "error",
341 |                 "source": {
342 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-button-dropdown.component.ts",
343 |                   "position": {
344 |                     "startLine": 7,
345 |                     "startColumn": 4,
346 |                     "endLine": 10,
347 |                     "endColumn": 13
348 |                   }
349 |                 }
350 |               },
351 |               {
352 |                 "message": "🔗🔲  Element <code>select</code> in attribute <code>class</code> uses deprecated class <code>dropdown</code>. Use <code>DSDropdown</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-dropdown--overview\" target=\"_blank\">Learn more</a>.",
353 |                 "severity": "error",
354 |                 "source": {
355 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
356 |                   "position": {
357 |                     "startLine": 25,
358 |                     "endLine": 28,
359 |                     "endColumn": 9
360 |                   }
361 |                 }
362 |               },
363 |               {
364 |                 "message": "🔗🎨 ️ The selector's class <code>dropdown</code> is deprecated. Use <code>DSDropdown</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-dropdown--overview\" target=\"_blank\">Learn more</a>.",
365 |                 "severity": "error",
366 |                 "source": {
367 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
368 |                   "position": {
369 |                     "startLine": 50,
370 |                     "startColumn": 1,
371 |                     "endLine": 54,
372 |                     "endColumn": 1
373 |                   }
374 |                 }
375 |               }
376 |             ]
377 |           },
378 |           "title": "Usage coverage for DSDropdown component",
379 |           "description": "Coverage audit for DSDropdown component. Matching classes: dropdown, legacy-dropdown, custom-dropdown"
380 |         },
381 |         {
382 |           "slug": "coverage-dsaccordion",
383 |           "displayValue": "0 classes found",
384 |           "value": 0,
385 |           "score": 1,
386 |           "details": {
387 |             "issues": []
388 |           },
389 |           "title": "Usage coverage for DSAccordion component",
390 |           "description": "Coverage audit for DSAccordion component. Matching classes: accordion, collapse-panel, legacy-accordion"
391 |         },
392 |         {
393 |           "slug": "coverage-dsalert",
394 |           "displayValue": "6 classes found",
395 |           "value": 6,
396 |           "score": 0,
397 |           "details": {
398 |             "issues": [
399 |               {
400 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-alert--overview\" target=\"_blank\">Learn more</a>.",
401 |                 "severity": "error",
402 |                 "source": {
403 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
404 |                   "position": {
405 |                     "startLine": 46,
406 |                     "startColumn": 4,
407 |                     "endLine": 46,
408 |                     "endColumn": 51
409 |                   }
410 |                 }
411 |               },
412 |               {
413 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-alert--overview\" target=\"_blank\">Learn more</a>.",
414 |                 "severity": "error",
415 |                 "source": {
416 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts",
417 |                   "position": {
418 |                     "startLine": 6,
419 |                     "startColumn": 4,
420 |                     "endLine": 6,
421 |                     "endColumn": 67
422 |                   }
423 |                 }
424 |               },
425 |               {
426 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-alert--overview\" target=\"_blank\">Learn more</a>.",
427 |                 "severity": "error",
428 |                 "source": {
429 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert.component.ts",
430 |                   "position": {
431 |                     "startLine": 5,
432 |                     "startColumn": 1,
433 |                     "endLine": 5,
434 |                     "endColumn": 62
435 |                   }
436 |                 }
437 |               },
438 |               {
439 |                 "message": "✏️🎨 ️ The selector's class <code>alert</code> is deprecated. Use <code>DSAlert</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-alert--overview\" target=\"_blank\">Learn more</a>.",
440 |                 "severity": "error",
441 |                 "source": {
442 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert.component.ts",
443 |                   "position": {
444 |                     "startLine": 7,
445 |                     "startColumn": 1,
446 |                     "endLine": 10,
447 |                     "endColumn": 7
448 |                   }
449 |                 }
450 |               },
451 |               {
452 |                 "message": "🔗🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>alert</code>. Use <code>DSAlert</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-alert--overview\" target=\"_blank\">Learn more</a>.",
453 |                 "severity": "error",
454 |                 "source": {
455 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
456 |                   "position": {
457 |                     "startLine": 22,
458 |                     "endLine": 22,
459 |                     "endColumn": 61
460 |                   }
461 |                 }
462 |               },
463 |               {
464 |                 "message": "🔗🎨 ️ The selector's class <code>alert</code> is deprecated. Use <code>DSAlert</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-alert--overview\" target=\"_blank\">Learn more</a>.",
465 |                 "severity": "error",
466 |                 "source": {
467 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
468 |                   "position": {
469 |                     "startLine": 43,
470 |                     "startColumn": 1,
471 |                     "endLine": 47,
472 |                     "endColumn": 1
473 |                   }
474 |                 }
475 |               }
476 |             ]
477 |           },
478 |           "title": "Usage coverage for DSAlert component",
479 |           "description": "Coverage audit for DSAlert component. Matching classes: alert, notification, legacy-alert"
480 |         },
481 |         {
482 |           "slug": "coverage-dstooltip",
483 |           "displayValue": "5 classes found",
484 |           "value": 5,
485 |           "score": 0,
486 |           "details": {
487 |             "issues": [
488 |               {
489 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>tooltip</code>. Use <code>DSTooltip</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-tooltip--overview\" target=\"_blank\">Learn more</a>.",
490 |                 "severity": "error",
491 |                 "source": {
492 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
493 |                   "position": {
494 |                     "startLine": 52,
495 |                     "startColumn": 4,
496 |                     "endLine": 52,
497 |                     "endColumn": 42
498 |                   }
499 |                 }
500 |               },
501 |               {
502 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>tooltip</code>. Use <code>DSTooltip</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-tooltip--overview\" target=\"_blank\">Learn more</a>.",
503 |                 "severity": "error",
504 |                 "source": {
505 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-alert-tooltip-input.component.ts",
506 |                   "position": {
507 |                     "startLine": 8,
508 |                     "startColumn": 4,
509 |                     "endLine": 8,
510 |                     "endColumn": 45
511 |                   }
512 |                 }
513 |               },
514 |               {
515 |                 "message": "🔗🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>tooltip</code>. Use <code>DSTooltip</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-tooltip--overview\" target=\"_blank\">Learn more</a>.",
516 |                 "severity": "error",
517 |                 "source": {
518 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
519 |                   "position": {
520 |                     "startLine": 31,
521 |                     "endLine": 31,
522 |                     "endColumn": 49
523 |                   }
524 |                 }
525 |               },
526 |               {
527 |                 "message": "🔗🎨 ️ The selector's class <code>tooltip</code> is deprecated. Use <code>DSTooltip</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-tooltip--overview\" target=\"_blank\">Learn more</a>.",
528 |                 "severity": "error",
529 |                 "source": {
530 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
531 |                   "position": {
532 |                     "startLine": 57,
533 |                     "startColumn": 1,
534 |                     "endLine": 61,
535 |                     "endColumn": 1
536 |                   }
537 |                 }
538 |               },
539 |               {
540 |                 "message": "🔗🎨 ️ The selector's class <code>tooltip</code> is deprecated. Use <code>DSTooltip</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-tooltip--overview\" target=\"_blank\">Learn more</a>.",
541 |                 "severity": "error",
542 |                 "source": {
543 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
544 |                   "position": {
545 |                     "startLine": 63,
546 |                     "startColumn": 1,
547 |                     "endLine": 73,
548 |                     "endColumn": 1
549 |                   }
550 |                 }
551 |               }
552 |             ]
553 |           },
554 |           "title": "Usage coverage for DSTooltip component",
555 |           "description": "Coverage audit for DSTooltip component. Matching classes: tooltip, legacy-tooltip, info-bubble"
556 |         },
557 |         {
558 |           "slug": "coverage-dsbreadcrumb",
559 |           "displayValue": "4 classes found",
560 |           "value": 4,
561 |           "score": 0,
562 |           "details": {
563 |             "issues": [
564 |               {
565 |                 "message": "✏️🔲  Element <code>nav</code> in attribute <code>class</code> uses deprecated class <code>breadcrumb</code>. Use <code>DSBreadcrumb</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview\" target=\"_blank\">Learn more</a>.",
566 |                 "severity": "error",
567 |                 "source": {
568 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
569 |                   "position": {
570 |                     "startLine": 62,
571 |                     "startColumn": 4,
572 |                     "endLine": 64,
573 |                     "endColumn": 10
574 |                   }
575 |                 }
576 |               },
577 |               {
578 |                 "message": "🔗🔲  Element <code>nav</code> in attribute <code>class</code> uses deprecated class <code>breadcrumb</code>. Use <code>DSBreadcrumb</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview\" target=\"_blank\">Learn more</a>.",
579 |                 "severity": "error",
580 |                 "source": {
581 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
582 |                   "position": {
583 |                     "startLine": 34,
584 |                     "endLine": 36,
585 |                     "endColumn": 6
586 |                   }
587 |                 }
588 |               },
589 |               {
590 |                 "message": "🔗🎨 ️ The selector's class <code>breadcrumb</code> is deprecated. Use <code>DSBreadcrumb</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview\" target=\"_blank\">Learn more</a>.",
591 |                 "severity": "error",
592 |                 "source": {
593 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
594 |                   "position": {
595 |                     "startLine": 76,
596 |                     "startColumn": 1,
597 |                     "endLine": 79,
598 |                     "endColumn": 1
599 |                   }
600 |                 }
601 |               },
602 |               {
603 |                 "message": "🔗🎨 ️ The selector's class <code>breadcrumb</code> is deprecated. Use <code>DSBreadcrumb</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-breadcrumb--overview\" target=\"_blank\">Learn more</a>.",
604 |                 "severity": "error",
605 |                 "source": {
606 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
607 |                   "position": {
608 |                     "startLine": 81,
609 |                     "startColumn": 1,
610 |                     "endLine": 84,
611 |                     "endColumn": 1
612 |                   }
613 |                 }
614 |               }
615 |             ]
616 |           },
617 |           "title": "Usage coverage for DSBreadcrumb component",
618 |           "description": "Coverage audit for DSBreadcrumb component. Matching classes: breadcrumb, legacy-breadcrumb, nav-breadcrumb"
619 |         },
620 |         {
621 |           "slug": "coverage-dsprogressbar",
622 |           "displayValue": "4 classes found",
623 |           "value": 4,
624 |           "score": 0,
625 |           "details": {
626 |             "issues": [
627 |               {
628 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>progress-bar</code>. Use <code>DSProgressBar</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-progressbar--overview\" target=\"_blank\">Learn more</a>.",
629 |                 "severity": "error",
630 |                 "source": {
631 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-modal-progress.component.ts",
632 |                   "position": {
633 |                     "startLine": 13,
634 |                     "startColumn": 4,
635 |                     "endLine": 15,
636 |                     "endColumn": 10
637 |                   }
638 |                 }
639 |               },
640 |               {
641 |                 "message": "✏️🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>progress-bar</code>. Use <code>DSProgressBar</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-progressbar--overview\" target=\"_blank\">Learn more</a>.",
642 |                 "severity": "error",
643 |                 "source": {
644 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/bad-mixed.component.ts",
645 |                   "position": {
646 |                     "startLine": 29,
647 |                     "startColumn": 4,
648 |                     "endLine": 31,
649 |                     "endColumn": 10
650 |                   }
651 |                 }
652 |               },
653 |               {
654 |                 "message": "🔗🔲  Element <code>div</code> in attribute <code>class</code> uses deprecated class <code>progress-bar</code>. Use <code>DSProgressBar</code> instead. <a href=\"https://storybook.company.com/latest/?path=/docs/components-progressbar--overview\" target=\"_blank\">Learn more</a>.",
655 |                 "severity": "error",
656 |                 "source": {
657 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.html",
658 |                   "position": {
659 |                     "startLine": 17,
660 |                     "endLine": 19,
661 |                     "endColumn": 6
662 |                   }
663 |                 }
664 |               },
665 |               {
666 |                 "message": "🔗🎨 ️ The selector's class <code>progress-bar</code> is deprecated. Use <code>DSProgressBar</code> and delete the styles. <a href=\"https://storybook.company.com/latest/?path=/docs/components-progressbar--overview\" target=\"_blank\">Learn more</a>.",
667 |                 "severity": "error",
668 |                 "source": {
669 |                   "file": "plugins/ds-component-coverage/mocks/fixtures/coverage-audit/demo/mixed-external-assets.component.css",
670 |                   "position": {
671 |                     "startLine": 32,
672 |                     "startColumn": 1,
673 |                     "endLine": 35,
674 |                     "endColumn": 1
675 |                   }
676 |                 }
677 |               }
678 |             ]
679 |           },
680 |           "title": "Usage coverage for DSProgressBar component",
681 |           "description": "Coverage audit for DSProgressBar component. Matching classes: progress-bar, loading-bar, legacy-progress"
682 |         },
683 |         {
684 |           "slug": "coverage-dsslider",
685 |           "displayValue": "0 classes found",
686 |           "value": 0,
687 |           "score": 1,
688 |           "details": {
689 |             "issues": []
690 |           },
691 |           "title": "Usage coverage for DSSlider component",
692 |           "description": "Coverage audit for DSSlider component. Matching classes: slider, range-slider, legacy-slider"
693 |         },
694 |         {
695 |           "slug": "coverage-dsnavbar",
696 |           "displayValue": "0 classes found",
697 |           "value": 0,
698 |           "score": 1,
699 |           "details": {
700 |             "issues": []
701 |           },
702 |           "title": "Usage coverage for DSNavbar component",
703 |           "description": "Coverage audit for DSNavbar component. Matching classes: navbar, navigation, legacy-navbar"
704 |         }
705 |       ],
706 |       "description": "A plugin to measure and assert usage of styles in an Angular project."
707 |     }
708 |   ]
709 | }
710 | 
```
Page 9/10FirstPrevNextLast