#
tokens: 49675/50000 94/473 files (page 2/7)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 7. Use http://codebase.md/push-based/angular-toolkit-mcp?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/angular-ast-utils/src/lib/ts.walk.ts:
--------------------------------------------------------------------------------

```typescript
import * as ts from 'typescript';
import { getDecorators, isDecorator } from 'typescript';

/**
 * Visits all decorators in a given class.
 */
export function visitAngularDecorators(
  node: ts.Node,
  visitor: (decorator: ts.Decorator) => void,
) {
  const decorators = getDecorators(node as ts.HasDecorators);
  if (!decorators?.length) return;

  decorators.forEach((decorator: ts.Decorator) => {
    if (!isDecorator(decorator)) return;
    visitor(decorator);
  });
}

// 👀 visit every decorator
// ✔ in visitor use `isDecorator`or `isComponentDecorator`

/**
 * Visits all properties inside a Angular decorator. e.g. @Component()
 */
export function visitAngularDecoratorProperties(
  decorator: ts.Decorator,
  visitor: (node: ts.PropertyAssignment) => void,
) {
  if (!ts.isCallExpression(decorator.expression)) {
    return;
  }
  const args = decorator.expression.arguments;
  if (!args?.length || !ts.isObjectLiteralExpression(args[0])) {
    return;
  }
  args[0].properties.forEach((prop: ts.ObjectLiteralElementLike) => {
    if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) return;
    visitor(prop);
  });
}

```

--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------

```yaml
name: CI

on:
  push:
    branches:
      - main
  pull_request:

permissions:
  actions: read
  contents: read

jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # This enables task distribution via Nx Cloud
      # Run this command as early as possible, before dependencies are installed
      # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
      # Uncomment this line to enable task distribution
      # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="build"

      # Cache node_modules
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - run: npm ci
      - uses: nrwl/nx-set-shas@v4
      - run: npx nx format:check

      # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
      # - run: npx nx-cloud record -- echo Hello World
      # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
      - run: npx nx affected -t lint test build

```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/ai/API.md:
--------------------------------------------------------------------------------

```markdown
# Angular AST Utils

Small, zero‑dependency helpers for **parsing and analysing Angular code** inside Model Context Protocol (MCP) tools.

## Minimal usage

```ts
import { parseComponents } from 'angular-ast-utils';

const components = await parseComponents(['src/app/app.component.ts']);
console.log(components[0].className); // → 'AppComponent'
```

## Key Features

- **Component Parsing**: Parse Angular components from TypeScript files
- **Template Analysis**: Visit and analyze Angular template AST nodes
- **Style Processing**: Process component styles and stylesheets
- **Angular Unit Discovery**: Find components, directives, pipes, and services
- **Decorator Traversal**: Walk through Angular decorators and their properties
- **CSS Class Detection**: Check for CSS classes in `[ngClass]` bindings

## Documentation map

| Doc                            | What you'll find                            |
| ------------------------------ | ------------------------------------------- |
| [FUNCTIONS.md](./FUNCTIONS.md) | A–Z quick reference for every public symbol |
| [EXAMPLES.md](./EXAMPLES.md)   | Runnable scenarios with expected output     |

```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/src/lib/decorator-config.visitor.inline-styles.spec.ts:
--------------------------------------------------------------------------------

```typescript
/* eslint-disable prefer-const */
import { describe, it, expect } from 'vitest';
import * as ts from 'typescript';
import { classDecoratorVisitor } from './decorator-config.visitor.js';

describe('DecoratorConfigVisitor - inline styles', () => {
  it('extracts inline styles when styles is provided as single string', async () => {
    const source = [
      "import { Component } from '@angular/core';",
      '@Component({',
      "  selector: 'x-comp',",
      '  styles: `',
      '    .btn { color: red; }',
      '  `',
      '})',
      'export class XComponent {}',
    ].join('\n');

    const sourceFile = ts.createSourceFile(
      'cmp.ts',
      source,
      ts.ScriptTarget.Latest,
      true,
    );

    const visitor = await classDecoratorVisitor({ sourceFile });
    ts.visitEachChild(sourceFile, visitor, undefined);

    expect(visitor.components).toHaveLength(1);
    const cmp = visitor.components[0] as any;
    expect(cmp.styles).toBeDefined();
    expect(Array.isArray(cmp.styles)).toBe(true);
    expect(cmp.styles.length).toBe(1);
    expect(cmp.styles[0]).toEqual(
      expect.objectContaining({ filePath: 'cmp.ts' }),
    );
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-usage-graph/utils/path-resolver.ts:
--------------------------------------------------------------------------------

```typescript
import * as fs from 'fs';
import * as path from 'path';
import { toUnixPath } from '@code-pushup/utils';
import { DEPENDENCY_ANALYSIS_CONFIG } from '../models/config.js';

const { resolveExtensions, indexFiles } = DEPENDENCY_ANALYSIS_CONFIG;

const SUFFIXES = ['', ...resolveExtensions, ...indexFiles.map((ext) => ext)];

// Memoized fs.existsSync (tiny utility)
const existsCache = new Map<string, boolean>();
const exists = (p: string): boolean => {
  const cached = existsCache.get(p);
  if (cached !== undefined) return cached;
  const ok = fs.existsSync(p);
  existsCache.set(p, ok);
  return ok;
};

export const isExternal = (p: string): boolean =>
  !p.startsWith('./') && !p.startsWith('../') && !path.isAbsolute(p);

export const resolveDependencyPath = (
  importPath: string,
  fromFile: string,
  basePath: string,
): string | null => {
  if (isExternal(importPath)) return null;

  const base = path.resolve(
    path.dirname(fromFile),
    importPath.replace(/\/$/, ''),
  );
  for (const s of SUFFIXES) {
    const candidate = base + s;
    if (exists(candidate)) {
      return toUnixPath(path.relative(basePath, candidate));
    }
  }
  return null;
};

```

--------------------------------------------------------------------------------
/packages/angular-mcp/webpack.config.cjs:
--------------------------------------------------------------------------------

```
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
const { join } = require('path');
const webpack = require('webpack');

module.exports = {
  output: {
    path: join(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.ts', '.js', '.mjs', '.cjs', '.json'],
  },
  externals: [
    // Keep Node.js built-ins external
    function ({ request }, callback) {
      if (/^node:/.test(request)) {
        return callback(null, 'commonjs ' + request);
      }
      callback();
    },
  ],
  module: {
    rules: [
      {
        test: /\.d\.ts$/,
        loader: 'ignore-loader',
      },
    ],
  },
  plugins: [
    new NxAppWebpackPlugin({
      target: 'node',
      compiler: 'tsc',
      main: './src/main.ts',
      tsConfig: './tsconfig.app.json',
      assets: [
        './src/assets',
        {
          input: '.',
          glob: 'README.md',
          output: '.',
        },
      ],
      optimization: false,
      outputHashing: 'none',
      generatePackageJson: true,
      externalDependencies: 'none',
    }),
    new webpack.BannerPlugin({
      banner: '#!/usr/bin/env node',
      raw: true,
      entryOnly: true,
    }),
  ],
};

```

--------------------------------------------------------------------------------
/testing/vitest-setup/vite.config.ts:
--------------------------------------------------------------------------------

```typescript
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
import * as path from 'path';

export default defineConfig({
  root: __dirname,
  cacheDir: '../../node_modules/.vite/testing/testing-vitest-setup',
  plugins: [
    dts({
      entryRoot: 'src',
      tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'),
    }),
  ],
  // Uncomment this if you are using workers.
  // worker: {
  //  plugins: [ nxViteTsPaths() ],
  // },
  // Configuration for building your library.
  // See: https://vitejs.dev/guide/build.html#library-mode
  build: {
    outDir: './dist',
    emptyOutDir: true,
    reportCompressedSize: true,
    commonjsOptions: {
      transformMixedEsModules: true,
    },
    lib: {
      // Could also be a dictionary or array of multiple entry points.
      entry: 'src/index.ts',
      name: 'testing-vitest-setup',
      fileName: 'index',
      // Change this to the formats you want to support.
      // Don't forget to update your package.json as well.
      formats: ['es'],
    },
    rollupOptions: {
      // External packages that should not be bundled into your library.
      external: [],
    },
  },
});

```

--------------------------------------------------------------------------------
/packages/shared/typescript-ast-utils/src/lib/utils.ts:
--------------------------------------------------------------------------------

```typescript
import * as ts from 'typescript';

import { QUOTE_REGEX } from './constants.js';

export function isComponentDecorator(decorator: ts.Decorator): boolean {
  return isDecorator(decorator, 'Component');
}

export function getDecorators(node: ts.Node): readonly ts.Decorator[] {
  if (ts.getDecorators) {
    return ts.getDecorators(node as ts.HasDecorators) ?? [];
  }
  if (hasDecorators(node)) {
    return node.decorators;
  }
  return [];
}

export function isDecorator(
  decorator: ts.Decorator,
  decoratorName?: string,
): boolean {
  const nodeObject = decorator?.expression as unknown as {
    expression: ts.Expression;
  };
  const identifierObject = nodeObject?.expression;

  if (identifierObject == null || !ts.isIdentifier(identifierObject))
    return false;

  if (decoratorName == null) {
    return true;
  }
  return identifierObject.text === decoratorName;
}

export function removeQuotes(node: ts.Node, sourceFile: ts.SourceFile): string {
  return node.getText(sourceFile).replace(QUOTE_REGEX, '');
}

export function hasDecorators(
  node: ts.Node,
): node is ts.Node & { decorators: readonly ts.Decorator[] } {
  return 'decorators' in node && Array.isArray(node.decorators);
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-mixed-external-assets.component.css:
--------------------------------------------------------------------------------

```css
/* ❌ Bad: Legacy button styles */
.btn {
  padding: 10px 15px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

/* ❌ Bad: Custom modal styles */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
}

.modal-content {
  text-align: center;
}

/* ❌ Bad: Custom progress bar */
.progress-bar {
  width: 100%;
  background-color: #ddd;
}

.progress {
  height: 10px;
  background-color: green;
}

/* ❌ Bad: Legacy alert */
.alert {
  padding: 10px;
  border: 1px solid red;
  background-color: pink;
}

/* ❌ Bad: Hardcoded dropdown */
.dropdown {
  padding: 5px;
  border: 1px solid #ccc;
  background-color: white;
}

/* ❌ Bad: Custom tooltip */
.tooltip {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.tooltip:hover::after {
  content: 'This is a tooltip';
  position: absolute;
  background: black;
  color: white;
  padding: 5px;
  border-radius: 5px;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

/* ❌ Bad: Breadcrumb styling */
.breadcrumb {
  display: flex;
  gap: 5px;
}

.breadcrumb span {
  color: blue;
  cursor: pointer;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-1/bad-mixed-external-assets-1.component.css:
--------------------------------------------------------------------------------

```css
/* ❌ Bad: Legacy button styles */
.btn {
  padding: 10px 15px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

/* ❌ Bad: Custom modal styles */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
}

.modal-content {
  text-align: center;
}

/* ❌ Bad: Custom progress bar */
.progress-bar {
  width: 100%;
  background-color: #ddd;
}

.progress {
  height: 10px;
  background-color: green;
}

/* ❌ Bad: Legacy alert */
.alert {
  padding: 10px;
  border: 1px solid red;
  background-color: pink;
}

/* ❌ Bad: Hardcoded dropdown */
.dropdown {
  padding: 5px;
  border: 1px solid #ccc;
  background-color: white;
}

/* ❌ Bad: Custom tooltip */
.tooltip {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.tooltip:hover::after {
  content: 'This is a tooltip';
  position: absolute;
  background: black;
  color: white;
  padding: 5px;
  border-radius: 5px;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

/* ❌ Bad: Breadcrumb styling */
.breadcrumb {
  display: flex;
  gap: 5px;
}

.breadcrumb span {
  color: blue;
  cursor: pointer;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-2/bad-mixed-external-assets-2.component.css:
--------------------------------------------------------------------------------

```css
/* ❌ Bad: Legacy button styles */
.btn {
  padding: 10px 15px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

/* ❌ Bad: Custom modal styles */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
}

.modal-content {
  text-align: center;
}

/* ❌ Bad: Custom progress bar */
.progress-bar {
  width: 100%;
  background-color: #ddd;
}

.progress {
  height: 10px;
  background-color: green;
}

/* ❌ Bad: Legacy alert */
.alert {
  padding: 10px;
  border: 1px solid red;
  background-color: pink;
}

/* ❌ Bad: Hardcoded dropdown */
.dropdown {
  padding: 5px;
  border: 1px solid #ccc;
  background-color: white;
}

/* ❌ Bad: Custom tooltip */
.tooltip {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.tooltip:hover::after {
  content: 'This is a tooltip';
  position: absolute;
  background: black;
  color: white;
  padding: 5px;
  border-radius: 5px;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

/* ❌ Bad: Breadcrumb styling */
.breadcrumb {
  display: flex;
  gap: 5px;
}

.breadcrumb span {
  color: blue;
  cursor: pointer;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-3/bad-mixed-external-assets-3.component.css:
--------------------------------------------------------------------------------

```css
/* ❌ Bad: Legacy button styles */
.btn {
  padding: 10px 15px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

/* ❌ Bad: Custom modal styles */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
}

.modal-content {
  text-align: center;
}

/* ❌ Bad: Custom progress bar */
.progress-bar {
  width: 100%;
  background-color: #ddd;
}

.progress {
  height: 10px;
  background-color: green;
}

/* ❌ Bad: Legacy alert */
.alert {
  padding: 10px;
  border: 1px solid red;
  background-color: pink;
}

/* ❌ Bad: Hardcoded dropdown */
.dropdown {
  padding: 5px;
  border: 1px solid #ccc;
  background-color: white;
}

/* ❌ Bad: Custom tooltip */
.tooltip {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.tooltip:hover::after {
  content: 'This is a tooltip';
  position: absolute;
  background: black;
  color: white;
  padding: 5px;
  border-radius: 5px;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

/* ❌ Bad: Breadcrumb styling */
.breadcrumb {
  display: flex;
  gap: 5px;
}

.breadcrumb span {
  color: blue;
  cursor: pointer;
}

```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/mixed-external-assets.component.css:
--------------------------------------------------------------------------------

```css
/* ❌ Bad: Legacy button styles */
.btn {
  padding: 10px 15px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

/* ❌ Bad: Custom modal styles */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
}

.modal-content {
  text-align: center;
}

/* ❌ Bad: Custom progress bar */
.progress-bar {
  width: 100%;
  background-color: #ddd;
}

.progress {
  height: 10px;
  background-color: green;
}

/* ❌ Bad: Legacy alert */
.alert {
  padding: 10px;
  border: 1px solid red;
  background-color: pink;
}

/* ❌ Bad: Hardcoded dropdown */
.dropdown {
  padding: 5px;
  border: 1px solid #ccc;
  background-color: white;
}

/* ❌ Bad: Custom tooltip */
.tooltip {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.tooltip:hover::after {
  content: 'This is a tooltip';
  position: absolute;
  background: black;
  color: white;
  padding: 5px;
  border-radius: 5px;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

/* ❌ Bad: Breadcrumb styling */
.breadcrumb {
  display: flex;
  gap: 5px;
}

.breadcrumb span {
  color: blue;
  cursor: pointer;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/ui/modal/src/modal.component.ts:
--------------------------------------------------------------------------------

```typescript
import {
  ChangeDetectionStrategy,
  Component,
  Signal,
  ViewEncapsulation,
  booleanAttribute,
  computed,
  inject,
  input,
  signal,
} from '@angular/core';

export const DS_MODAL_VARIANT_ARRAY = [
  'surface-lowest',
  'surface-low',
  'surface',
] as const;
export type DsModalVariant = (typeof DS_MODAL_VARIANT_ARRAY)[number];
export class DsModalContext {
  inverse: Signal<boolean> = signal(false); // Explicit type
}

@Component({
  selector: 'ds-modal',
  template: `<ng-content />`,
  host: {
    class: 'ds-modal',
    role: 'dialog',
    'aria-label': 'Modal dialog',
    '[class.ds-modal-inverse]': 'inverse()',
    '[class.ds-modal-bottom-sheet]': 'bottomSheet()',
    '[class]': 'hostClass()',
  },
  providers: [DsModalContext],
  standalone: true,
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DsModal {
  inverse = input(false, { transform: booleanAttribute });
  bottomSheet = input(false, { transform: booleanAttribute });
  variant = input<DsModalVariant>('surface');

  private context = inject(DsModalContext);

  protected hostClass = computed(() => `ds-modal-${this.variant()}`);

  constructor() {
    this.context.inverse = computed(() => this.inverse());
  }
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/tools.ts:
--------------------------------------------------------------------------------

```typescript
import { ToolsConfig } from '@push-based/models';
import {
  reportViolationsTools,
  reportAllViolationsTools,
} from './report-violations/index.js';
import { getProjectDependenciesTools } from './project/get-project-dependencies.tool.js';
import { reportDeprecatedCssTools } from './project/report-deprecated-css.tool.js';
import { buildComponentUsageGraphTools } from './component-usage-graph/index.js';
import { getDsComponentDataTools } from './component/get-ds-component-data.tool.js';
import { listDsComponentsTools } from './component/list-ds-components.tool.js';
import { getDeprecatedCssClassesTools } from './component/get-deprecated-css-classes.tool.js';
import {
  buildComponentContractTools,
  diffComponentContractTools,
  listComponentContractsTools,
} from './component-contract/index.js';

export const dsTools: ToolsConfig[] = [
  // Project tools
  ...reportViolationsTools,
  ...reportAllViolationsTools,
  ...getProjectDependenciesTools,
  ...reportDeprecatedCssTools,
  ...buildComponentUsageGraphTools,
  // Component contract tools
  ...buildComponentContractTools,
  ...diffComponentContractTools,
  ...listComponentContractsTools,
  // Component tools
  ...getDsComponentDataTools,
  ...listDsComponentsTools,
  ...getDeprecatedCssClassesTools,
];

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/prompts/prompt-registry.ts:
--------------------------------------------------------------------------------

```typescript
import { PromptSchema } from '@modelcontextprotocol/sdk/types.js';
import { z } from 'zod';

/**
 * Registry of available prompts for the Angular MCP server.
 *
 * This registry is currently empty but provides the infrastructure
 * for future prompt implementations. Prompts allow LLMs to request
 * structured text generation with specific parameters.
 *
 * When adding prompts:
 * 1. Add the prompt schema to PROMPTS with name, description, and arguments
 * 2. Add the corresponding implementation to PROMPTS_IMPL
 *
 * Example implementation:
 * ```typescript
 * PROMPTS['component-docs'] = {
 *   name: 'component-docs',
 *   description: 'Generate documentation for Angular components',
 *   arguments: [
 *     {
 *       name: 'componentName',
 *       description: 'Name of the component to document',
 *       required: true,
 *     },
 *   ],
 * };
 *
 * PROMPTS_IMPL['component-docs'] = {
 *   text: (args) => `Generate docs for ${args.componentName}...`,
 * };
 * ```
 */
export const PROMPTS: Record<string, z.infer<typeof PromptSchema>> = {
  // Future prompts will be added here
} as const;

export const PROMPTS_IMPL: Record<
  string,
  { text: (args: Record<string, string>) => string }
> = {
  // Future prompt implementations will be added here
} as const;

```

--------------------------------------------------------------------------------
/tools/nx-advanced-profile.bin.js:
--------------------------------------------------------------------------------

```javascript
import { mkdirSync, writeFileSync } from 'node:fs';
import { parseArgs } from 'node:util';
import { nxRunWithPerfLogging } from './nx-advanced-profile.js';

const { values } = parseArgs({
  options: {
    args: {
      type: 'string',
    },
    verbose: {
      type: 'boolean',
      short: 'v',
    },
    noPatch: {
      type: 'boolean',
      short: 'p',
    },
    outDir: {
      type: 'string',
      short: 'd',
    },
    outFile: {
      type: 'string',
      short: 'f',
    },
  },
});

const {
  args = ['show', 'projects'].join(','),
  verbose,
  noPatch,
  outDir = '.nx-profiling',
  outFile = `nx-${args.split(',').join('-')}.${Date.now()}.profile.json`,
} = values;

// Run the function with arguments and write the collected timings to a JSON file.
nxRunWithPerfLogging(args.split(','), {
  verbose,
  noPatch,
  onData: (perfProfileEvent) => {
    // console.log(perfProfileEvent);
  },
  beforeExit: (profile) => {
    // @TODO figure out why profile directly does not show the flames but profile.traceEvents does
    const profileStdout = JSON.stringify(profile.traceEvents, null, 2);
    mkdirSync(outDir, { recursive: true });
    writeFileSync(`${outDir}/${outFile}`, profileStdout);
    if (verbose) {
      console.log(profileStdout);
    }
  },
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/types.ts:
--------------------------------------------------------------------------------

```typescript
export type BaseToolSchema = {
  cwd: string;
};

export type ToolInput<
  TSchema extends Record<
    string,
    { inputSchema: { properties: Record<string, unknown> } }
  >,
  T extends keyof TSchema,
> = {
  [K in keyof TSchema[T]['inputSchema']['properties']]: TSchema[T]['inputSchema']['properties'][K] extends {
    type: 'string';
  }
    ? string
    : TSchema[T]['inputSchema']['properties'][K] extends {
          type: 'array';
          items: { type: 'string' };
        }
      ? string[]
      : TSchema[T]['inputSchema']['properties'][K] extends {
            type: 'array';
            items: { type: 'object'; properties: Record<string, unknown> };
          }
        ? Array<{
            [P in keyof TSchema[T]['inputSchema']['properties'][K]['items']['properties']]: TSchema[T]['inputSchema']['properties'][K]['items']['properties'][P] extends {
              type: 'string';
            }
              ? string
              : TSchema[T]['inputSchema']['properties'][K]['items']['properties'][P] extends {
                    type: 'array';
                    items: { type: 'string' };
                  }
                ? string[]
                : never;
          }>
        : never;
};
export type NamedRecord<T extends string> = Record<T, { name: T }>;

```

--------------------------------------------------------------------------------
/packages/shared/models/ai/API.md:
--------------------------------------------------------------------------------

```markdown
# Models

Simple **TypeScript types** for Angular MCP toolkit shared interfaces and utilities.

## Minimal usage

```ts
import { type CliArgsObject, type ToolsConfig } from '@push-based/models';

// CLI argument types
const args: CliArgsObject = {
  directory: './src',
  componentName: 'DsButton',
  _: ['command'],
};

// MCP tool configuration
const toolConfig: ToolsConfig = {
  schema: {
    name: 'my-tool',
    description: 'A custom tool',
    inputSchema: {
      type: 'object',
      properties: {},
    },
  },
  handler: async (request) => {
    return { content: [{ type: 'text', text: 'Result' }] };
  },
};
```

## Key Features

- **CLI Types**: Type-safe command line argument handling
- **MCP Integration**: Model Context Protocol tool schema definitions and handlers
- **Diagnostics**: Interface for objects that can report issues and diagnostics
- **Lightweight**: Minimal dependencies, focused on essential shared types

## Documentation map

| Doc                            | What you'll find                            |
| ------------------------------ | ------------------------------------------- |
| [FUNCTIONS.md](./FUNCTIONS.md) | A–Z quick reference for every public symbol |
| [EXAMPLES.md](./EXAMPLES.md)   | Runnable scenarios with expected output     |

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/ui/segmented-control/src/segmented-option.component.ts:
--------------------------------------------------------------------------------

```typescript
import {
  ChangeDetectionStrategy,
  Component,
  TemplateRef,
  ViewEncapsulation,
  computed,
  contentChild,
  inject,
  input,
  output,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

import { rxHostPressedListener } from '@frontend/ui/rx-host-listener';

import { DsSegmentedControl } from './segmented-control.component';

@Component({
  selector: 'ds-segmented-option',
  template: `<ng-content />`,
  standalone: true,
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DsSegmentedOption {
  private segmentedControl = inject(DsSegmentedControl);

  readonly title = input('');
  readonly name = input.required<string>();

  readonly selectOption = output<string>();

  readonly customTemplate = contentChild<TemplateRef<any>>('dsTemplate');

  readonly selected = computed(
    () => this.segmentedControl.selectedOption() === this,
  );
  readonly focusVisible = computed(
    () => this.segmentedControl.focusVisibleOption() === this,
  );
  readonly focused = computed(
    () => this.segmentedControl.focusedOption() === this,
  );

  constructor() {
    rxHostPressedListener()
      .pipe(takeUntilDestroyed())
      .subscribe(() => this.selectOption.emit(this.name()));
  }
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/diff/models/schema.ts:
--------------------------------------------------------------------------------

```typescript
import { ToolSchemaOptions } from '@push-based/models';
import { COMMON_ANNOTATIONS } from '../../../shared/index.js';

/**
 * Schema for diffing component contracts
 */
export const diffComponentContractSchema: ToolSchemaOptions = {
  name: 'diff_component_contract',
  description:
    'Compare before/after contracts for parity and surface breaking changes.',
  inputSchema: {
    type: 'object',
    properties: {
      saveLocation: {
        type: 'string',
        description:
          'Path where to save the diff result file. Supports both absolute and relative paths.',
      },
      contractBeforePath: {
        type: 'string',
        description:
          'Path to the contract file before refactoring. Supports both absolute and relative paths.',
      },
      contractAfterPath: {
        type: 'string',
        description:
          'Path to the contract file after refactoring. Supports both absolute and relative paths.',
      },
      dsComponentName: {
        type: 'string',
        description: 'The name of the design system component being used',
        default: '',
      },
    },
    required: ['saveLocation', 'contractBeforePath', 'contractAfterPath'],
  },
  annotations: {
    title: 'Diff Component Contract',
    ...COMMON_ANNOTATIONS.readOnly,
  },
};

```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/src/lib/parse-component.ts:
--------------------------------------------------------------------------------

```typescript
import { toUnixPath } from '@code-pushup/utils';
import * as ts from 'typescript';

import { classDecoratorVisitor } from './decorator-config.visitor.js';
import { ParsedComponent } from './types.js';

/**
 * Parses Angular components from a `FastFindInFiles` result.
 * It uses `typescript` to parse the components source files and extract the decorators.
 * From the decorators, it extracts the `@Component` decorator and its properties.
 * The used properties are `templateUrl`, `template`, `styles`, and `styleUrls`.
 *
 * @param files
 */
export async function parseComponents(
  files: string[],
): Promise<ParsedComponent[]> {
  const filePaths = new Set(files.map((filePath) => toUnixPath(filePath)));

  const program = ts.createProgram([...filePaths], {
    target: ts.ScriptTarget.Latest,
    module: ts.ModuleKind.ESNext,
    experimentalDecorators: true,
  });

  const sourceFiles: ts.SourceFile[] = program
    .getSourceFiles()
    .filter((file: ts.SourceFile) => filePaths.has(file.fileName));

  const results: ParsedComponent[] = [];
  //sourceFiles
  for (const sourceFile of sourceFiles) {
    const visitor = await classDecoratorVisitor({ sourceFile });

    ts.visitEachChild(sourceFile, visitor, undefined);
    results.push(...visitor.components);
  }

  return results;
}

```

--------------------------------------------------------------------------------
/packages/shared/styles-ast-utils/ai/API.md:
--------------------------------------------------------------------------------

```markdown
# Styles AST Utils

Small, zero‑dependency helpers for **parsing and analyzing CSS/SCSS stylesheets** using PostCSS inside Model Context Protocol (MCP) tools.

## Minimal usage

```ts
import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils';

const result = parseStylesheet('.btn { color: red; }', 'styles.css');
const visitor = {
  visitRule: (rule) => console.log(rule.selector), // → '.btn'
};
visitEachChild(result.root, visitor);
```

## Key Features

- **Stylesheet Parsing**: Parse CSS/SCSS content using PostCSS with safe parsing
- **AST Traversal**: Multiple traversal strategies for visiting CSS nodes
- **Visitor Pattern**: Flexible visitor interface for processing different node types
- **Source Location Mapping**: Convert AST nodes to linkable source locations
- **Line Number Preservation**: Maintain accurate line numbers for error reporting
- **Safe Parsing**: Graceful handling of malformed CSS using postcss-safe-parser

## Documentation map

| Doc                            | What you'll find                            |
| ------------------------------ | ------------------------------------------- |
| [FUNCTIONS.md](./FUNCTIONS.md) | A–Z quick reference for every public symbol |
| [EXAMPLES.md](./EXAMPLES.md)   | Runnable scenarios with expected output     |

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/validation/file-existence.ts:
--------------------------------------------------------------------------------

```typescript
import * as fs from 'node:fs';
import * as path from 'node:path';
import { AngularMcpServerOptions } from './angular-mcp-server-options.schema.js';

export function validateAngularMcpServerFilesExist(
  config: AngularMcpServerOptions,
) {
  const root = config.workspaceRoot;

  if (!fs.existsSync(root)) {
    throw new Error(`workspaceRoot directory does not exist: ${root}`);
  }

  const missingFiles: string[] = [];

  // Always require uiRoot, optional: storybookDocsRoot, deprecatedCssClassesPath
  const dsPaths = [
    config.ds.storybookDocsRoot
      ? { label: 'ds.storybookDocsRoot', relPath: config.ds.storybookDocsRoot }
      : null,
    config.ds.deprecatedCssClassesPath
      ? {
          label: 'ds.deprecatedCssClassesPath',
          relPath: config.ds.deprecatedCssClassesPath,
        }
      : null,
    { label: 'ds.uiRoot', relPath: config.ds.uiRoot },
  ].filter(Boolean) as { label: string; relPath: string }[];

  for (const { label, relPath } of dsPaths) {
    const absPath = path.resolve(root, relPath);
    if (!fs.existsSync(absPath)) {
      missingFiles.push(`${label} (resolved to: ${absPath})`);
    }
  }

  if (missingFiles.length > 0) {
    throw new Error(
      `The following required files or directories do not exist:\n` +
        missingFiles.join('\n'),
    );
  }
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/spec/meta.generator.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from 'vitest';

import { generateMeta } from '../utils/meta.generator.js';

interface ParsedComponentStub {
  className?: string;
  selector?: string;
}

describe('generateMeta', () => {
  const templatePath = 'src/app/foo.component.html';

  it('uses parsed component className and selector when provided', () => {
    const parsedComponent: ParsedComponentStub = {
      className: 'FooComponent',
      selector: 'app-foo',
    };

    const meta = generateMeta(templatePath, parsedComponent as any, false);

    expect(meta.name).toBe('FooComponent');
    expect(meta.selector).toBe('app-foo');
    expect(meta.sourceFile).toBe(templatePath);
    expect(meta.templateType).toBe('external');
    expect(meta.hash).toBe('');
    expect(typeof meta.generatedAt).toBe('string');
  });

  it('falls back to filename when className or selector missing', () => {
    const parsedComponent: ParsedComponentStub = {};

    const meta = generateMeta(templatePath, parsedComponent as any);

    expect(meta.name).toBe('foo.component');
    expect(meta.selector).toBe('.foo.component');
  });

  it('sets templateType to inline when flag is true', () => {
    const parsedComponent: ParsedComponentStub = {};

    const meta = generateMeta(templatePath, parsedComponent as any, true);

    expect(meta.templateType).toBe('inline');
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/validation/angular-mcp-server-options.schema.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from 'zod';
import * as path from 'path';

const isAbsolutePath = (val: string) => path.isAbsolute(val);
const isRelativePath = (val: string) => !path.isAbsolute(val);

export const AngularMcpServerOptionsSchema = z.object({
  workspaceRoot: z.string().refine(isAbsolutePath, {
    message:
      'workspaceRoot must be an absolute path to the repository root where MCP server is working (e.g., /path/to/workspace-root)',
  }),
  ds: z.object({
    storybookDocsRoot: z
      .string()
      .optional()
      .refine((val) => val === undefined || isRelativePath(val), {
        message:
          'ds.storybookDocsRoot must be a relative path from workspace root to the storybook project root (e.g., path/to/storybook/components)',
      }),
    deprecatedCssClassesPath: z
      .string()
      .optional()
      .refine((val) => val === undefined || isRelativePath(val), {
        message:
          'ds.deprecatedCssClassesPath must be a relative path from workspace root to the file component to deprecated css classes mapping (e.g., path/to/components-config.js)',
      }),
    uiRoot: z.string().refine(isRelativePath, {
      message:
        'ds.uiRoot must be a relative path from workspace root to the components folder (e.g., path/to/components)',
    }),
  }),
});

export type AngularMcpServerOptions = z.infer<
  typeof AngularMcpServerOptionsSchema
>;

```

--------------------------------------------------------------------------------
/packages/shared/styles-ast-utils/src/lib/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { Issue } from '@code-pushup/models';
import { Rule } from 'postcss';

/**
 * Convert a Root to an Issue source object and adjust its position based on startLine.
 * It creates a "linkable" source object for the issue.
 * By default, the source location is 0 indexed, so we add 1 to the startLine to make it work in file links.
 *
 * @param rule The AST rule to convert into a linkable source object.
 * @param startLine The positions of the asset contain the style rules.
 */
export function styleAstRuleToSource(
  { source }: Pick<Rule, 'source'>,
  startLine = 0, // 0 indexed
): Issue['source'] {
  if (source?.input.file == null) {
    throw new Error(
      'style parsing was not initialized with a file path. Check the postcss options.',
    );
  }
  const offset = startLine - 1; // -1 because PostCss is 1 indexed so we have to substract 1 to make is work in 0 based index

  return {
    file: source.input.file,
    position: {
      startLine: (source?.start?.line ?? 1) + offset + 1, // +1 because the code works 0 indexed and file links work 1 indexed.
      ...(source?.start?.column && { startColumn: source?.start?.column }),
      ...(source?.end?.line && { endLine: source?.end?.line + offset + 1 }), // +1 because the code works 0 indexed and file links work 1 indexed.
      ...(source?.end?.column && { endColumn: source?.end?.column }),
    },
  };
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/shared/violation-analysis/types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Shared types for violation analysis across file and folder reporting modules
 */

export interface BaseViolationOptions {
  cwd?: string;
  directory: string;
  componentName: string;
  deprecatedCssClassesPath?: string;
}

export interface BaseViolationIssue {
  message: string;
  source?: {
    file: string;
    position?: {
      startLine: number;
    };
  };
}

export interface BaseViolationAudit {
  details?: {
    issues?: BaseViolationIssue[];
  };
  title: string;
  score: number;
}

export interface BaseViolationResult {
  audits: BaseViolationAudit[];
  [key: string]: unknown;
}

// Coverage analysis types (moved from project/utils/coverage-helpers.ts)
export interface ReportCoverageParams {
  cwd?: string;
  returnRawData?: boolean;
  outputFormat?: 'text';
  directory: string;
  dsComponents: DsComponent[];
}

export interface DsComponent {
  componentName: string;
  deprecatedCssClasses: string[];
}

export interface FormattedCoverageResult {
  textOutput: string;
  rawData?: {
    rawPluginResult: BaseViolationResult;
    pluginOptions: any;
  };
}

// Shared file grouping types (consolidated from different modules)
export interface FileGroup {
  message: string;
  lines: number[];
}

export interface FileGroups {
  [fileName: string]: FileGroup;
}

// Performance-optimized path cache
export interface PathCache {
  [key: string]: string;
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/validation/ds-components.schema.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from 'zod';

/**
 * Expected format example:
 * [
 *   {
 *     componentName: 'DsButton',
 *     deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button']
 *   },
 *   {
 *     componentName: 'DsModal',
 *     deprecatedCssClasses: ['modal']
 *   }
 * ]
 */

const EXAMPLE_FORMAT = `Expected: [{ componentName: 'DsButton', deprecatedCssClasses: ['btn'] }]`;

export const DsComponentSchema = z.object({
  componentName: z.string({
    required_error:
      'Missing required "componentName" field. Must be a string like "DsButton".',
    invalid_type_error:
      'Invalid "componentName" type. Must be a string like "DsButton".',
  }),
  deprecatedCssClasses: z.array(
    z.string({
      required_error:
        'CSS class name must be a string. Example: "btn" or "legacy-button".',
      invalid_type_error: 'CSS class name must be a string.',
    }),
    {
      required_error:
        'Missing required "deprecatedCssClasses" field. Must be an array like ["btn", "legacy-button"].',
      invalid_type_error:
        'Invalid "deprecatedCssClasses" type. Must be an array of strings.',
    },
  ),
});

export const DsComponentsArraySchema = z.array(DsComponentSchema, {
  required_error: `Configuration must be an array of component objects. ${EXAMPLE_FORMAT}`,
  invalid_type_error: `Invalid configuration format. Must export an array. ${EXAMPLE_FORMAT}`,
});

```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/ai/API.md:
--------------------------------------------------------------------------------

```markdown
# DS Component Coverage

Small, zero‑dependency helpers for **measuring and asserting usage of Design System components** in Angular projects by detecting deprecated CSS classes.

## Minimal usage

```ts
import { dsComponentCoveragePlugin } from '@push-based/ds-component-coverage';

const plugin = dsComponentCoveragePlugin({
  directory: './src/app',
  dsComponents: [
    {
      componentName: 'DsButton',
      deprecatedCssClasses: ['btn', 'button'],
      docsUrl: 'https://design-system.com/button',
    },
  ],
});
```

## Key Features

- **CSS Class Detection**: Find deprecated CSS classes in templates and stylesheets
- **Design System Migration**: Track migration progress from legacy styles to DS components
- **Template Analysis**: Scan Angular templates for class usage in various binding types
- **Style Analysis**: Detect deprecated class definitions in component styles
- **Code Pushup Integration**: Built-in plugin for Code Pushup auditing framework
- **Comprehensive Reporting**: Generate detailed reports with file locations and suggestions

## Documentation map

| Doc                            | What you'll find                            |
| ------------------------------ | ------------------------------------------- |
| [FUNCTIONS.md](./FUNCTIONS.md) | A–Z quick reference for every public symbol |
| [EXAMPLES.md](./EXAMPLES.md)   | Runnable scenarios with expected output     |

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/ui/modal/src/modal-header/modal-header.component.ts:
--------------------------------------------------------------------------------

```typescript
import {
  ChangeDetectionStrategy,
  Component,
  ViewEncapsulation,
  computed,
  inject,
  input,
} from '@angular/core';

import { DsModalContext } from '../modal.component';

export const DS_MODAL_HEADER_VARIANT_ARRAY = [
  'surface-lowest',
  'surface-low',
  'surface',
  'surface-high',
  'nav-bg',
] as const;
export type DsModalHeaderVariant =
  (typeof DS_MODAL_HEADER_VARIANT_ARRAY)[number];

@Component({
  selector: 'ds-modal-header',
  standalone: true,
  template: `
    <div class="ds-modal-header-container">
      <div class="ds-modal-header-start">
        <ng-content select="[slot=start]" />
      </div>
      <div class="ds-modal-header-center">
        <ng-content select="[slot=center]" />
        <ng-content select="ds-modal-header-drag, [modal-header-image]" />
      </div>
      <div class="ds-modal-header-end">
        <ng-content select="[slot=end]" />
      </div>
    </div>
  `,
  host: {
    class: 'ds-modal-header',
    '[class]': 'hostClass()',
    '[class.ds-modal-header-inverse]': 'context.inverse()',
    role: 'dialog',
    'aria-label': 'Modal header dialog',
  },
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
})
export class DsModalHeader {
  variant = input<DsModalHeaderVariant>('surface');
  protected context = inject(DsModalContext);

  protected hostClass = computed(() => `ds-modal-header-${this.variant()}`);
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/first-case/dashboard-demo.component.scss:
--------------------------------------------------------------------------------

```scss
.demo-container {
  min-height: 100vh;
  background: #f9fafb;
  transition: background-color 0.2s ease;
}

.demo-container.dark {
  background: #111827;
}

.demo-content {
  padding: 2rem;
  max-width: 1200px;
  margin: 0 auto;
}

.demo-content h2 {
  color: #1f2937;
  margin-bottom: 1rem;
}

.demo-content p {
  color: #6b7280;
  margin-bottom: 2rem;
}

.demo-actions {
  display: flex;
  gap: 1rem;
  margin-bottom: 2rem;
  flex-wrap: wrap;
}

.demo-button {
  padding: 0.5rem 1rem;
  background: #3b82f6;
  color: white;
  border: none;
  border-radius: 0.375rem;
  cursor: pointer;
  font-size: 0.875rem;
  transition: background-color 0.2s ease;
}

.demo-button:hover {
  background: #2563eb;
}

.demo-log {
  background: white;
  border-radius: 0.5rem;
  padding: 1.5rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}

.demo-log h3 {
  margin: 0 0 1rem 0;
  color: #1f2937;
  font-size: 1.125rem;
}

.log-entries {
  max-height: 300px;
  overflow-y: auto;
}

.log-entry {
  padding: 0.5rem;
  border-bottom: 1px solid #f3f4f6;
  font-size: 0.875rem;
  color: #374151;
  font-family: monospace;
}

.log-entry:last-child {
  border-bottom: none;
}

/* Dark mode styles */
.dark .demo-content h2 {
  color: #f9fafb;
}

.dark .demo-content p {
  color: #d1d5db;
}

.dark .demo-log {
  background: #374151;
}

.dark .demo-log h3 {
  color: #f9fafb;
}

.dark .log-entry {
  color: #d1d5db;
  border-bottom-color: #4b5563;
} 
```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/utils/styles.collector.ts:
--------------------------------------------------------------------------------

```typescript
import { readFileSync } from 'node:fs';
import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils';
import { selectorMatches } from './css-match.js';
import type {
  StyleDeclarations,
  DomStructure,
} from '../../shared/models/types.js';
import type { Declaration, Rule } from 'postcss';

/**
 * Collect styles with explicit DOM relationships
 */
export async function collectStylesV2(
  scssPath: string,
  dom: DomStructure,
): Promise<StyleDeclarations> {
  const styles: StyleDeclarations = { sourceFile: scssPath, rules: {} };
  const scssContent = readFileSync(scssPath, 'utf-8');
  const parsedStyles = parseStylesheet(scssContent, scssPath);

  if (parsedStyles.root.type === 'root') {
    visitEachChild(parsedStyles.root, {
      visitRule: (rule: Rule) => {
        const properties: Record<string, string> = {};

        rule.walkDecls?.((decl: Declaration) => {
          properties[decl.prop] = decl.value;
        });

        styles.rules[rule.selector] = {
          appliesTo: findMatchingDomElements(rule.selector, dom),
          properties,
        };
      },
    });
  }

  return styles;
}

/**
 * Find DOM elements that match a CSS selector
 */
function findMatchingDomElements(
  cssSelector: string,
  dom: DomStructure,
): string[] {
  return Object.entries(dom)
    .filter(([domKey, element]) =>
      selectorMatches(cssSelector, domKey, element),
    )
    .map(([domKey]) => domKey);
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/first-case/dashboard-demo.component.html:
--------------------------------------------------------------------------------

```html
<div class="demo-container">
  <app-dashboard-header
    [badgeType]="'premium'"
    [badgeSize]="'medium'"
    [animated]="true"
    [pulsing]="false"
    [dismissible]="true"
    [userProfile]="userProfile()"
    [darkMode]="darkMode()"
    (searchPerformed)="onSearchPerformed($event)"
    (badgeDismissed)="onBadgeDismissed()"
    (notificationClicked)="onNotificationClicked($event)"
    (userActionClicked)="onUserActionClicked($event)"
    (themeToggled)="onThemeToggled($event)">
    
    <!-- Custom icon for the offer badge -->
    <span slot="start">⭐</span>
    
    <!-- Custom badge content -->
    Premium Features Available!
  </app-dashboard-header>
  
  <div class="demo-content">
    <h2>Dashboard Content</h2>
    <p>This is a demo of the complex dashboard header component.</p>
    
    <div class="demo-actions">
      <button (click)="toggleTheme()" class="demo-button">
        Toggle Theme (Current: {{ darkMode() ? 'Dark' : 'Light' }})
      </button>
      
      <button (click)="changeUser()" class="demo-button">
        Change User
      </button>
      
      <button (click)="addNotification()" class="demo-button">
        Add Notification
      </button>
    </div>
    
    <div class="demo-log">
      <h3>Event Log:</h3>
      <div class="log-entries">
        @for (entry of eventLog(); track $index) {
          <div class="log-entry">{{ entry }}</div>
        }
      </div>
    </div>
  </div>
</div> 
```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/utils/element-helpers.ts:
--------------------------------------------------------------------------------

```typescript
import type {
  TmplAstElement,
  ASTWithSource,
} from '@angular/compiler' with { 'resolution-mode': 'import' };

/**
 * Extract bindings from a template element
 */
export function extractBindings(element: TmplAstElement) {
  return element.inputs.map((input) => ({
    type: getBindingType(input.name),
    name: input.name,
    source: (input.value as ASTWithSource).source || '',
    sourceSpan: input.sourceSpan
      ? {
          start: input.sourceSpan.start.offset,
          end: input.sourceSpan.end.offset,
          file: input.sourceSpan.start.file.url,
        }
      : undefined,
  }));
}

/**
 * Extract attributes from a template element
 */
export function extractAttributes(element: TmplAstElement) {
  return element.attributes.map((attr) => ({
    type: 'attribute' as const,
    name: attr.name,
    source: attr.value,
  }));
}

/**
 * Extract events from a template element
 */
export function extractEvents(element: TmplAstElement) {
  return element.outputs.map((output) => ({
    name: output.name,
    handler: (output.handler as ASTWithSource).source || '',
  }));
}

/**
 * Determine the binding type based on the binding name
 */
function getBindingType(
  bindingName: string,
): 'class' | 'style' | 'property' | 'attribute' {
  if (bindingName.startsWith('class.')) return 'class';
  if (bindingName.startsWith('style.')) return 'style';
  if (bindingName.startsWith('attr.')) return 'attribute';
  return 'property';
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component/get-deprecated-css-classes.tool.ts:
--------------------------------------------------------------------------------

```typescript
import { ToolSchemaOptions } from '@push-based/models';
import { createHandler } from '../shared/utils/handler-helpers.js';
import {
  createComponentInputSchema,
  COMMON_ANNOTATIONS,
} from '../shared/models/schema-helpers.js';
import { getDeprecatedCssClasses } from './utils/deprecated-css-helpers.js';

interface DeprecatedCssClassesOptions {
  componentName: string;
}

export const getDeprecatedCssClassesSchema: ToolSchemaOptions = {
  name: 'get-deprecated-css-classes',
  description: `List deprecated CSS classes for a DS component.`,
  inputSchema: createComponentInputSchema(
    'The class name of the component to get deprecated classes for (e.g., DsButton)',
  ),
  annotations: {
    title: 'Get Deprecated CSS Classes',
    ...COMMON_ANNOTATIONS.readOnly,
  },
};

export const getDeprecatedCssClassesHandler = createHandler<
  DeprecatedCssClassesOptions,
  string[]
>(
  getDeprecatedCssClassesSchema.name,
  async ({ componentName }, { cwd, deprecatedCssClassesPath }) => {
    if (!deprecatedCssClassesPath) {
      throw new Error(
        'Missing ds.deprecatedCssClassesPath. Provide --ds.deprecatedCssClassesPath in mcp.json file.',
      );
    }
    return await getDeprecatedCssClasses(
      componentName,
      deprecatedCssClassesPath,
      cwd,
    );
  },
  (result) => result,
);

export const getDeprecatedCssClassesTools = [
  {
    schema: getDeprecatedCssClassesSchema,
    handler: getDeprecatedCssClassesHandler,
  },
];

```

--------------------------------------------------------------------------------
/packages/shared/styles-ast-utils/src/lib/stylesheet.parse.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect } from 'vitest';
import { parseStylesheet } from './stylesheet.parse.js';
import { Rule } from 'postcss';

describe('parseStylesheet', () => {
  it('should have line numbers starting from 1', () => {
    const result = parseStylesheet(`.btn{ color: red; }`, 'styles.css').root;
    const { source = {} as Exclude<Rule['source'], undefined> } =
      result.nodes.at(0) as Rule;
    const { start, end } = source;

    expect(start?.line).toBe(1);
    expect(start?.column).toBe(1);
    expect(end?.line).toBe(1);
    expect(end?.column).toBe(19);
  });

  it('should have correct line number for starting line breaks', () => {
    const result = parseStylesheet(
      `

.btn{ color: red; }`,
      'styles.css',
    ).root;

    const { source = {} as Exclude<Rule['source'], undefined> } =
      result?.nodes?.at(0) as Rule;
    const { start, end } = source;

    expect(start?.line).toBe(3);
    expect(start?.column).toBe(1);
    expect(end?.line).toBe(3);
    expect(end?.column).toBe(19);
  });

  it('should have correct line number for spans', () => {
    const result = parseStylesheet(
      `
.btn{
  color: red;
}`,
      'styles.css',
    ).root;

    const { source = {} as Exclude<Rule['source'], undefined> } =
      result?.nodes?.at(0) as Rule;
    const { start, end } = source;

    expect(start?.line).toBe(2);
    expect(start?.column).toBe(1);
    expect(end?.line).toBe(4);
    expect(end?.column).toBe(1);
  });
});

```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/src/lib/runner/audits/ds-coverage/ds-coverage.audit.ts:
--------------------------------------------------------------------------------

```typescript
import { getCompCoverageAuditOutput } from './utils.js';
import { AuditOutputs, Issue } from '@code-pushup/models';
import {
  ParsedComponent,
  visitComponentStyles,
  visitComponentTemplate,
  Asset,
} from '@push-based/angular-ast-utils';
import type { ParsedTemplate } from '@angular/compiler' with { 'resolution-mode': 'import' };
import { ComponentReplacement } from './schema.js';
import { getClassUsageIssues } from './class-usage.utils.js';
import { getClassDefinitionIssues } from './class-definition.utils.js';

export function dsCompCoverageAuditOutputs(
  dsComponents: ComponentReplacement[],
  parsedComponents: ParsedComponent[],
): Promise<AuditOutputs> {
  return Promise.all(
    dsComponents.map(async (dsComponent) => {
      const allIssues = (
        await Promise.all(
          parsedComponents.flatMap(async (component) => {
            return [
              ...(await visitComponentTemplate(
                component,
                dsComponent,
                getClassUsageIssues as (
                  tokenReplacement: ComponentReplacement,
                  asset: Asset<ParsedTemplate>,
                ) => Promise<Issue[]>,
              )),
              ...(await visitComponentStyles(
                component,
                dsComponent,
                getClassDefinitionIssues,
              )),
            ];
          }),
        )
      ).flat();

      return getCompCoverageAuditOutput(dsComponent, allIssues);
    }),
  );
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-4.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-7 {
  text-align: center;
}

.modal {
  width: 100%;
}

.example-class-8 {
  height: 50px;
}

.card {
  box-shadow: 0 0 10px gray;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/shared/utils/component-validation.ts:
--------------------------------------------------------------------------------

```typescript
import { COMPONENT_REGEXES } from './regex-helpers.js';

/**
 * Validates that a component name is a valid Design System component name
 * Accepts both formats: "Button" and "DsButton"
 * @param componentName The component name to validate
 * @throws Error if the component name is invalid
 */
export function validateComponentName(
  componentName: unknown,
): asserts componentName is string {
  if (
    !componentName ||
    typeof componentName !== 'string' ||
    !COMPONENT_REGEXES.isValidDsComponent(componentName)
  ) {
    throw new Error(
      'Invalid component name. Must be a valid PascalCase string (e.g., "Button" or "DsButton").',
    );
  }
}

/**
 * Converts a Design System component name to kebab case
 * @param componentName The component name (e.g., "DsButton" or "Button")
 * @returns The kebab case name (e.g., "button")
 */
export function componentNameToKebabCase(componentName: string): string {
  const kebabCase = COMPONENT_REGEXES.toKebabCase(componentName);

  if (!kebabCase?.trim()?.length) {
    throw new Error(
      'Invalid component name. Must be a valid PascalCase string (e.g., "Button" or "DsButton").',
    );
  }

  return kebabCase;
}

/**
 * Creates a tag name from a component name
 * @param componentName The component name (e.g., "DsButton" or "Button")
 * @returns The tag name (e.g., "ds-button")
 */
export function componentNameToTagName(componentName: string): string {
  return `ds-${componentNameToKebabCase(componentName)}`;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-1.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-1 {
  color: blue;
}

.pill-with-badge {
  background-color: red;
}

.example-class-2 {
  margin: 10px;
}

.btn-primary {
  padding: 5px;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-2.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-3 {
  font-size: 14px;
}

.offer-badge {
  border: 1px solid black;
}

.example-class-4 {
  padding: 20px;
}

.nav-tabs {
  display: flex;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-3.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-5 {
  background-color: yellow;
}

.tab-nav-item {
  color: green;
}

.example-class-6 {
  border-radius: 5px;
}

.legacy-button {
  font-weight: bold;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-6.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-11 {
  font-family: Arial, sans-serif;
}

.divider {
  border-top: 1px solid #ccc;
}

.example-class-12 {
  padding-left: 15px;
}

.count {
  font-size: 12px;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-7.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-13 {
  margin-right: 10px;
}

.badge-circle {
  border-radius: 50%;
}

.example-class-14 {
  color: #333;
}

.custom-control-checkbox {
  display: inline-block;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-5.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-9 {
  line-height: 1.5;
}

.loading {
  animation: spin 2s linear infinite;
}

.example-class-10 {
  max-width: 200px;
}

.collapsible-container {
  overflow: hidden;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-8.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-15 {
  background: #f0f0f0;
}

.custom-control-radio {
  margin-bottom: 5px;
}

.example-class-16 {
  border: 2px solid #000;
}

.form-control-tabs-segmented-v2 {
  display: block;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-usage-graph/models/types.ts:
--------------------------------------------------------------------------------

```typescript
import { SourceFileLocation } from '@code-pushup/models';

export interface DependencyInfo {
  path: string;
  type: DependencyInfoType;
  resolved: boolean;
  resolvedPath?: string;
  componentName?: string;
  sourceFile?: string;
  source?: SourceFileLocation;
}

export interface FileInfo {
  type: string;
  size: number;
  dependencies: DependencyInfo[];
  lastModified: number;
  componentName?: string;
  isAngularComponent?: boolean;
  source?: string; // Optional - not stored in optimized version to save memory
}

export type ComponentUsageGraphResult = Record<string, FileInfo>;

export interface BuildComponentUsageGraphOptions {
  cwd: string;
  directory: string;
  workspaceRoot?: string;
}

export interface ComponentMetadata {
  className: string;
}

export interface ComponentGroup {
  componentFile?: [string, FileInfo];
  relatedFiles: [string, FileInfo][];
  hasReverseDeps: boolean;
}

export type DependencyInfoType =
  | 'import'
  | 'require'
  | 'dynamic-import'
  | 'css-import'
  | 'asset'
  | 'external'
  | 'reverse-dependency';

export type FileExtension =
  | '.ts'
  | '.js'
  | '.jsx'
  | '.tsx'
  | '.css'
  | '.scss'
  | '.sass'
  | '.less'
  | '.html';

export type FileType =
  | 'typescript'
  | 'typescript-react'
  | 'javascript'
  | 'javascript-react'
  | 'css'
  | 'scss'
  | 'sass'
  | 'less'
  | 'template';

// Legacy aliases for backward compatibility
export type DependencyGraphResult = ComponentUsageGraphResult;
export type BuildDependencyGraphOptions = BuildComponentUsageGraphOptions;

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-10.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-19 {
  border-bottom: 1px solid #ddd;
}

.form-control-tabs-segmented-v3 {
  padding: 5px;
}

.example-class-20 {
  margin-left: 20px;
}

.form-control-tabs-segmented-v4 {
  border-radius: 3px;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/new-styles-9.scss:
--------------------------------------------------------------------------------

```scss
// Example SCSS file with deprecated and non-deprecated classes
.example-class-17 {
  padding-top: 10px;
}

.form-control-tabs-segmented-flex {
  flex-direction: row;
}

.example-class-18 {
  font-size: 16px;
}

.form-control-tabs-segmented-v2-dark {
  background-color: #333;
}

.example-class-21 {
  color: red;
}

.example-class-22 {
  background-color: green;
}

.example-class-23 {
  font-size: 18px;
}

.example-class-24 {
  padding: 10px;
}

.example-class-25 {
  margin: 5px;
}

.example-class-26 {
  border: 1px solid black;
}

.example-class-27 {
  text-align: left;
}

.example-class-28 {
  line-height: 2;
}

.example-class-29 {
  font-weight: normal;
}

.example-class-30 {
  display: inline-block;
}

.example-class-31 {
  width: 50%;
}

.example-class-32 {
  height: 100px;
}

.example-class-33 {
  overflow: auto;
}

.example-class-34 {
  position: relative;
}

.example-class-35 {
  top: 10px;
}

.example-class-36 {
  left: 20px;
}

.example-class-37 {
  right: 30px;
}

.example-class-38 {
  bottom: 40px;
}

.example-class-39 {
  z-index: 1;
}

.example-class-40 {
  opacity: 0.5;
}

.example-class-41 {
  visibility: hidden;
}

.example-class-42 {
  cursor: pointer;
}

.example-class-43 {
  transition: all 0.3s ease;
}

.example-class-44 {
  transform: rotate(45deg);
}

.example-class-45 {
  animation: fadeIn 1s;
}

.example-class-46 {
  box-sizing: border-box;
}

.example-class-47 {
  content: '';
}

.example-class-48 {
  clip: rect(0, 0, 0, 0);
}

.example-class-49 {
  float: left;
}

.example-class-50 {
  clear: both;
}

```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/src/lib/runner/audits/ds-coverage/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { Audit, AuditOutput, Issue } from '@code-pushup/models';
import { pluralize, slugify } from '@code-pushup/utils';
import { ComponentReplacement } from './schema.js';

/**
 * Creates a scored audit output.
 * @returns Audit output.
 * @param componentReplacements
 */
export function getCompUsageAudits(
  componentReplacements: ComponentReplacement[],
): Audit[] {
  return componentReplacements.map((comp) => ({
    slug: getCompCoverageAuditSlug(comp),
    title: getCompCoverageAuditTitle(comp),
    description: getCompCoverageAuditDescription(comp),
  }));
}

/**
 * Creates a scored audit output.
 * @param componentName
 * @param issues
 * @returns Audit output.
 */
export function getCompCoverageAuditOutput(
  componentName: ComponentReplacement,
  issues: Issue[],
): AuditOutput {
  return {
    slug: getCompCoverageAuditSlug(componentName),
    displayValue: `${issues.length} ${pluralize('class', issues.length)} found`,
    score: issues.length === 0 ? 1 : 0,
    value: issues.length,
    details: {
      issues,
    },
  };
}

export function getCompCoverageAuditSlug({
  componentName,
}: ComponentReplacement): string {
  return slugify(`coverage-${componentName}`);
}
export function getCompCoverageAuditTitle({
  componentName,
}: ComponentReplacement): string {
  return `Usage coverage for ${componentName} component`;
}
export function getCompCoverageAuditDescription({
  componentName,
  deprecatedCssClasses,
}: ComponentReplacement): string {
  return `Coverage audit for ${componentName} component. Matching classes: ${deprecatedCssClasses.join(
    ', ',
  )}`;
}

```

--------------------------------------------------------------------------------
/packages/shared/utils/src/lib/file/file.resolver.ts:
--------------------------------------------------------------------------------

```typescript
import { existsSync } from 'fs';
import { readFile } from 'fs/promises';
import * as path from 'path';

export const fileResolverCache = new Map<string, Promise<string>>();

/**
 * Resolves a file content from the file system, caching the result
 * to avoid reading the same file multiple times.
 *
 * This function returns a Promise that resolves to the file content.
 * This is important to avoid reading the same file multiple times.
 * @param filePath
 */
export async function resolveFileCached(filePath: string): Promise<string> {
  const normalizedPath = path.normalize(filePath);
  if (!existsSync(normalizedPath)) {
    throw new Error(`File not found: ${normalizedPath}`);
  }

  if (fileResolverCache.has(normalizedPath)) {
    const cachedPromise = fileResolverCache.get(normalizedPath);
    if (cachedPromise) {
      return cachedPromise;
    }
  }

  const fileReadOperationPromise = resolveFile(filePath)
    .then((content) => {
      fileResolverCache.set(normalizedPath, Promise.resolve(content));
      return content;
    })
    .catch((ctx) => {
      fileResolverCache.delete(normalizedPath);
      throw ctx;
    });

  fileResolverCache.set(normalizedPath, fileReadOperationPromise);
  return fileReadOperationPromise;
}

/**
 * Resolves a file content from the file system directly, bypassing any cache.
 *
 * @param filePath
 */
export async function resolveFile(filePath: string): Promise<string> {
  const normalizedPath = path.normalize(filePath);
  if (!existsSync(normalizedPath)) {
    throw new Error(`File not found: ${normalizedPath}`);
  }
  return readFile(normalizedPath, 'utf-8');
}

```

--------------------------------------------------------------------------------
/tools/nx-advanced-profile.js:
--------------------------------------------------------------------------------

```javascript
import { fork } from 'node:child_process';
import { fileURLToPath } from 'node:url';

export async function nxRunWithPerfLogging(
  args,
  {
    verbose = false,
    noPatch = false,
    onData = () => {},
    onTraceEvent = () => {},
    onMetadata = () => {},
    beforeExit = () => {},
  } = {},
) {
  const patch = !noPatch;
  const nxUrl = await import.meta.resolve('nx');
  const nxPath = fileURLToPath(nxUrl);

  const profile = {
    metadata: {},
    traceEvents: [],
  };

  const forkArgs = [
    nxPath,
    args,
    {
      stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
      env: {
        ...process.env,
        NX_DAEMON: 'false',
        NX_CACHE: 'false',
        NX_PERF_LOGGING: 'true',
      },
      // Preload the patch file so that it applies before NX is loaded.
      execArgv: patch ? ['--require', './tools/perf_hooks.patch.js'] : [],
    },
  ];
  if (verbose) {
    console.log('Forking NX with args:', forkArgs);
  }

  const child = fork(...forkArgs);

  child.stdout?.on('data', (data) => {
    const lines = data.toString().split('\n');
    for (const line of lines) {
      onData(line);
      const res = line.split(':JSON:');

      if (res.length === 2) {
        const [prop, jsonString] = res;
        const perfProfileEvent = JSON.parse(jsonString?.trim() || '{}');
        if (prop === 'traceEvent') {
          onTraceEvent(perfProfileEvent);
          profile.traceEvents.push(perfProfileEvent);
        }
        if (prop === 'metadata') {
          onMetadata(perfProfileEvent);
          profile.metadata = perfProfileEvent;
        }
      }
    }
  });

  child.on('close', () => {
    beforeExit(profile);
  });
}

```

--------------------------------------------------------------------------------
/packages/shared/utils/src/lib/file/default-export-loader.ts:
--------------------------------------------------------------------------------

```typescript
import { pathToFileURL } from 'node:url';

/**
 * Dynamically imports an ES Module and extracts the default export.
 *
 * @param filePath - Absolute path to the ES module file to import
 * @returns The default export from the module
 * @throws Error if the module cannot be loaded or has no default export
 *
 * @example
 * ```typescript
 * const data = await loadDefaultExport('/path/to/config.js');
 * ```
 */
export async function loadDefaultExport<T = unknown>(
  filePath: string,
): Promise<T> {
  try {
    const fileUrl = pathToFileURL(filePath).toString();

    // In test environments (Vitest), use native import to avoid transformation issues
    // In production (webpack/bundled), use Function constructor to preserve dynamic import
    const isTestEnv =
      typeof process !== 'undefined' &&
      (process.env.NODE_ENV === 'test' ||
        process.env.VITEST === 'true' ||
        typeof (globalThis as Record<string, unknown>).vitest !== 'undefined');

    const module = isTestEnv
      ? await import(fileUrl)
      : await new Function('url', 'return import(url)')(fileUrl);

    if (!('default' in module)) {
      throw new Error(
        `No default export found in module. Expected ES Module format:\n` +
          `export default [...]\n\n` +
          `Available exports: ${Object.keys(module).join(', ') || 'none'}`,
      );
    }

    return module.default;
  } catch (ctx) {
    if (
      ctx instanceof Error &&
      ctx.message.includes('No default export found')
    ) {
      throw ctx;
    }
    throw new Error(
      `Failed to load module from ${filePath}: ${ctx instanceof Error ? ctx.message : String(ctx)}`,
    );
  }
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/shared/violation-analysis/base-analyzer.ts:
--------------------------------------------------------------------------------

```typescript
import * as process from 'node:process';
import { getDeprecatedCssClasses } from '../../component/utils/deprecated-css-helpers.js';
import { validateComponentName } from '../utils/component-validation.js';
import {
  BaseViolationOptions,
  BaseViolationResult,
  ReportCoverageParams,
} from './types.js';
import { analyzeProjectCoverage as collectFilesViolations } from './coverage-analyzer.js';

/**
 * Base analyzer for design system violations - shared logic between file and folder reporting
 */
export async function analyzeViolationsBase<T extends BaseViolationResult>(
  options: BaseViolationOptions,
): Promise<T> {
  const {
    cwd = process.cwd(),
    directory,
    componentName,
    deprecatedCssClassesPath,
  } = options;

  validateComponentName(componentName);

  if (!directory || typeof directory !== 'string') {
    throw new Error('Directory parameter is required and must be a string');
  }

  process.chdir(cwd);

  if (!deprecatedCssClassesPath) {
    throw new Error(
      'Missing ds.deprecatedCssClassesPath. Provide --ds.deprecatedCssClassesPath in mcp.json file.',
    );
  }

  const deprecatedCssClasses = await getDeprecatedCssClasses(
    componentName,
    deprecatedCssClassesPath,
    cwd,
  );

  const dsComponents = [
    {
      componentName,
      deprecatedCssClasses,
    },
  ];

  const params: ReportCoverageParams = {
    cwd,
    returnRawData: true,
    directory,
    dsComponents,
  };

  const result = await collectFilesViolations(params);

  if (!result.rawData?.rawPluginResult) {
    throw new Error('Failed to get raw plugin result for violation analysis');
  }

  return result.rawData.rawPluginResult as T;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/component-options.mjs:
--------------------------------------------------------------------------------

```
const dsComponents = [
  {
    componentName: 'DsPill',
    deprecatedCssClasses: [
      'pill-with-badge',
      'pill-with-badge-v2',
      'sports-pill',
    ],
  },
  {
    componentName: 'DsBadge',
    deprecatedCssClasses: ['offer-badge'],
  },
  {
    componentName: 'DsTabsModule',
    deprecatedCssClasses: ['tab-nav', 'nav-tabs', 'tab-nav-item'],
  },
  {
    componentName: 'DsButton',
    deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button'],
  },
  {
    componentName: 'DsModal',
    deprecatedCssClasses: ['modal'],
  },
  {
    componentName: 'DsCard',
    deprecatedCssClasses: ['card'],
  },
  {
    componentName: 'DsLoadingSpinner',
    deprecatedCssClasses: ['loading', 'loading-v2', 'loading-v3'],
  },
  {
    componentName: 'DsCardExpandable',
    deprecatedCssClasses: ['collapsible-container'],
  },
  {
    componentName: 'DsDivider',
    deprecatedCssClasses: ['divider'],
  },
  {
    componentName: 'DsNotificationBubble',
    deprecatedCssClasses: ['count', 'badge-circle'],
  },
  {
    componentName: 'DsCheckbox',
    deprecatedCssClasses: ['custom-control-checkbox'],
  },
  {
    componentName: 'DsRadioModule',
    deprecatedCssClasses: ['custom-control-radio'],
  },
  {
    componentName: 'DsSegmentedControlModule',
    deprecatedCssClasses: [
      'form-control-tabs-segmented-v2',
      'form-control-tabs-segmented-flex',
      'form-control-tabs-segmented-v2-dark',
      'form-control-tabs-segmented-v3',
      'form-control-tabs-segmented-v4',
      'form-control-tabs-segmented',
    ],
  },
  {
    componentName: 'DsSwitch',
    deprecatedCssClasses: ['custom-control-switcher'],
  },
];

export default dsComponents;

```

--------------------------------------------------------------------------------
/testing/vitest-setup/src/lib/fs-memfs.setup-file.ts:
--------------------------------------------------------------------------------

```typescript
import {
  MockInstance,
  afterEach,
  beforeEach,
  vi,
  beforeAll,
  afterAll,
} from 'vitest';

// Define the constant locally since cross-project imports cause build issues
const MEMFS_VOLUME = '/memfs';

/**
 * Mocks the fs and fs/promises modules with memfs.
 */

type Memfs = typeof import('memfs');

vi.mock('fs', async () => {
  const memfs: Memfs = await vi.importActual('memfs');
  return memfs.fs;
});

vi.mock('fs/promises', async () => {
  const memfs: Memfs = await vi.importActual('memfs');
  return memfs.fs.promises;
});

/**
 * Mocks the current working directory to MEMFS_VOLUME.
 * This is useful when you use relative paths in your code
 * @type {MockInstance<[], string>}
 *
 * @example
 * - `readFile('./file.txt')` reads MEMFS_VOLUME/file.txt
 * - `readFile(join(process.cwd(), 'file.txt'))` reads MEMFS_VOLUME/file.txt
 * - `readFile('file.txt')` reads file.txt
 */
let cwdSpy: MockInstance;

// This covers arrange blocks at the top of a "describe" block
beforeAll(() => {
  cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(MEMFS_VOLUME);
});

// Clear mock usage data in arrange blocks as well as usage of the API in each "it" block.
// docs: https://vitest.dev/api/mock.html#mockclear
beforeEach(() => {
  cwdSpy.mockClear();
});

// Restore mock implementation and usage data "it" block
// Mock implementations remain if given. => vi.fn(impl).mockRestore() === vi.fn(impl)
// docs: https://vitest.dev/api/mock.html#mockrestore
afterEach(() => {
  cwdSpy.mockRestore();
});

// Restore the original implementation after all "describe" block in a file
// docs: https://vitest.dev/api/mock.html#mockreset
afterAll(() => {
  cwdSpy.mockReset();
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/models/schema.ts:
--------------------------------------------------------------------------------

```typescript
import { ToolSchemaOptions } from '@push-based/models';
import { COMMON_ANNOTATIONS } from '../../../shared/index.js';

/**
 * Schema for building component contracts
 */
export const buildComponentContractSchema: ToolSchemaOptions = {
  name: 'build_component_contract',
  description:
    "Generate a static surface contract for a component's template and SCSS.",
  inputSchema: {
    type: 'object',
    properties: {
      saveLocation: {
        type: 'string',
        description:
          'Path where to save the contract file. Supports both absolute and relative paths.',
      },
      templateFile: {
        type: 'string',
        description:
          'Path to the component template file (.html). Optional - if not provided or if the path matches typescriptFile, will extract inline template from the component. Supports both absolute and relative paths.',
      },
      styleFile: {
        type: 'string',
        description:
          'Path to the component style file (.scss, .sass, .less, .css). Optional - if not provided or if the path matches typescriptFile, will extract inline styles from the component. Supports both absolute and relative paths.',
      },
      typescriptFile: {
        type: 'string',
        description:
          'Path to the TypeScript component file (.ts). Supports both absolute and relative paths.',
      },
      dsComponentName: {
        type: 'string',
        description: 'The name of the design system component being used',
        default: '',
      },
    },
    required: ['saveLocation', 'typescriptFile'],
  },
  annotations: {
    title: 'Build Component Contract',
    ...COMMON_ANNOTATIONS.readOnly,
  },
};

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component/utils/metadata-helpers.ts:
--------------------------------------------------------------------------------

```typescript
import { validateComponentName } from '../../shared/utils/component-validation.js';
import { getDeprecatedCssClasses } from './deprecated-css-helpers.js';
import { getComponentDocs } from './doc-helpers.js';
import { getComponentPathsInfo } from './paths-helpers.js';

export interface ComponentMetadataParams {
  componentName: string;
  storybookDocsRoot?: string;
  deprecatedCssClassesPath?: string;
  uiRoot?: string;
  cwd?: string;
}

export interface ComponentMetadataResult {
  sourcePath: string | null;
  importPath: string | null;
  tagName: string | null;
  api: string | null;
  overview: string | null;
  deprecatedCssClasses: string;
}

export async function analyzeComponentMetadata(
  params: ComponentMetadataParams,
): Promise<ComponentMetadataResult> {
  validateComponentName(params.componentName);

  const storybookDocsRoot = params.storybookDocsRoot || 'docs';
  const deprecatedCssClassesPath =
    params.deprecatedCssClassesPath || 'deprecated-css-classes.js';
  const uiRoot = params.uiRoot || 'libs/ui';
  const cwd = params.cwd || process.cwd();

  const documentation = getComponentDocs(
    params.componentName,
    storybookDocsRoot,
  );
  const deprecatedCssClassesList = await getDeprecatedCssClasses(
    params.componentName,
    deprecatedCssClassesPath,
    cwd,
  );
  const componentPaths = getComponentPathsInfo(
    params.componentName,
    uiRoot,
    cwd,
  );

  return {
    sourcePath: componentPaths.srcPath,
    importPath: componentPaths.importPath,
    tagName: documentation.tagName,
    api: documentation.api,
    overview: documentation.overview,
    deprecatedCssClasses: JSON.stringify(deprecatedCssClassesList),
  };
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/project/utils/styles-report-helpers.ts:
--------------------------------------------------------------------------------

```typescript
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils';
import { findAllFiles } from '@push-based/utils';
import type { Rule } from 'postcss';

export interface StyleFileReport {
  filePath: string;
  foundClasses: {
    className: string;
    selector: string;
    lineNumber?: number;
  }[];
}

const STYLE_EXT = new Set(['.css', '.scss', '.sass', '.less']);

const isStyleFile = (f: string) => STYLE_EXT.has(path.extname(f).toLowerCase());
const escapeRegex = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

export async function findStyleFiles(dir: string): Promise<string[]> {
  const files: string[] = [];
  for await (const file of findAllFiles(dir, isStyleFile)) {
    files.push(file);
  }
  return files;
}

export async function analyzeStyleFile(
  filePath: string,
  deprecated: string[],
): Promise<StyleFileReport> {
  const css = await fs.readFile(filePath, 'utf8');
  const { root } = await parseStylesheet(css, filePath);

  const found: StyleFileReport['foundClasses'] = [];
  const master = new RegExp(
    `\\.(${deprecated.map(escapeRegex).join('|')})(?![\\w-])`,
    'g',
  );

  // Handle both Document_ and Root_ types
  if (root.type !== 'root') {
    return { filePath, foundClasses: found };
  }

  visitEachChild(root, {
    visitRule(rule: Rule) {
      let match;
      while ((match = master.exec(rule.selector)) !== null) {
        found.push({
          className: match[1],
          selector: rule.selector,
          lineNumber: rule.source?.start?.line,
        });
      }
      master.lastIndex = 0;
    },
  });

  return { filePath, foundClasses: found };
}

```

--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------

```
import nx from '@nx/eslint-plugin';
import unicorn from 'eslint-plugin-unicorn';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  // Base Nx configurations
  ...nx.configs['flat/base'],
  ...nx.configs['flat/typescript'],
  ...nx.configs['flat/javascript'],

  // Global ignores
  {
    ignores: [
      '**/dist',
      '**/vite.config.*.timestamp*',
      '**/vitest.config.*.timestamp*',
      '**/mocks/**',
      '**/fixtures/**',
      '**/__snapshot__/**',
      '**/__snapshots__/**',
      '**/__tests__/**',
      '**/__mocks__/**',
      '**/test-fixtures/**',
      '**/e2e/fixtures/**',
    ],
  },

  // Nx module boundaries and TypeScript rules
  {
    files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
    rules: {
      '@nx/enforce-module-boundaries': [
        'error',
        {
          enforceBuildableLibDependency: true,
          allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?js$'],
          depConstraints: [
            {
              sourceTag: '*',
              onlyDependOnLibsWithTags: ['*'],
            },
          ],
        },
      ],
      '@typescript-eslint/no-unused-vars': [
        'error',
        {
          argsIgnorePattern: '^_',
          destructuredArrayIgnorePattern: '^_',
          ignoreRestSiblings: true,
        },
      ],
    },
  },

  // Unicorn plugin rules
  {
    files: [
      '**/*.ts',
      '**/*.tsx',
      '**/*.cts',
      '**/*.mts',
      '**/*.js',
      '**/*.jsx',
      '**/*.cjs',
      '**/*.mjs',
    ],
    plugins: {
      unicorn: unicorn,
    },
    rules: {
      'unicorn/prefer-top-level-await': 'error',
      'unicorn/catch-error-name': ['error', { name: 'ctx' }],
    },
  },
);

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component/utils/deprecated-css-helpers.ts:
--------------------------------------------------------------------------------

```typescript
import * as fs from 'fs';
import { resolveCrossPlatformPath } from '../../shared/utils/cross-platform-path.js';
import { loadDefaultExport } from '@push-based/utils';

export interface DeprecatedCssComponent {
  componentName: string;
  deprecatedCssClasses: string[];
}

/**
 * Retrieves deprecated CSS classes for a specific component from a configuration file
 * @param componentName - The name of the component to get deprecated classes for
 * @param deprecatedCssClassesPath - Path to the file containing deprecated CSS classes configuration
 * @param cwd - Current working directory
 * @returns Array of deprecated CSS classes for the component
 * @throws Error if file not found, invalid format, or component not found
 */
export async function getDeprecatedCssClasses(
  componentName: string,
  deprecatedCssClassesPath: string,
  cwd: string,
): Promise<string[]> {
  if (
    !deprecatedCssClassesPath ||
    typeof deprecatedCssClassesPath !== 'string'
  ) {
    throw new Error('deprecatedCssClassesPath must be a string path');
  }

  const absPath = resolveCrossPlatformPath(cwd, deprecatedCssClassesPath);
  if (!fs.existsSync(absPath)) {
    throw new Error(`File not found at deprecatedCssClassesPath: ${absPath}`);
  }

  const dsComponents =
    await loadDefaultExport<DeprecatedCssComponent[]>(absPath);

  if (!Array.isArray(dsComponents)) {
    throw new Error('Invalid export: expected dsComponents to be an array');
  }

  const componentData = dsComponents.find(
    (item) => item.componentName === componentName,
  );

  if (!componentData) {
    throw new Error(
      `No deprecated classes found for component: ${componentName}`,
    );
  }

  return componentData.deprecatedCssClasses;
}

```

--------------------------------------------------------------------------------
/testing/utils/src/lib/e2e-setup.ts:
--------------------------------------------------------------------------------

```typescript
import path from 'node:path';
import fs from 'node:fs/promises';

export function getE2eAppProjectName(): string | undefined {
  const e2eProjectName = process.env['NX_TASK_TARGET_PROJECT'] ?? '';
  if (e2eProjectName == null) {
    console.warn('NX_TASK_TARGET_PROJECT is not set.');
  }
  return e2eProjectName ? `${e2eProjectName}-app` : undefined;
}

export async function setupE2eApp(
  fixtureProjectName: string,
  e2eFixtures?: string,
) {
  const targetProjectName =
    getE2eAppProjectName() ?? fixtureProjectName + '-e2e-app';
  const fixture = path.join(
    __dirname,
    `../../../e2e/fixtures/${fixtureProjectName}`,
  );
  const target = path.join(
    __dirname,
    `../../../e2e/__test__/${targetProjectName}`,
  );
  try {
    await fs.stat(fixture);
  } catch (ctx) {
    console.warn(
      `Fixture folder not found. Did you change the file or move it? Error: ${
        (ctx as Error).message
      }`,
    );
    return;
  }

  // copy fixtures folder
  await fs.rm(target, { recursive: true, force: true });
  await fs.cp(fixture, target, {
    recursive: true,
    force: true,
    filter(source: string, _: string): boolean | Promise<boolean> {
      return !source.includes('node_modules') && !source.includes('dist');
    },
  });

  // adjust package.json#nx to new location and rename project
  const packageJson = (
    await fs.readFile(path.join(target, 'package.json'), 'utf-8')
  ).toString();
  await fs.writeFile(
    path.join(target, 'package.json'),
    packageJson
      .replaceAll('fixtures', '__test__')
      .replaceAll(fixtureProjectName, targetProjectName),
  );
  // add e2e fixtures
  if (e2eFixtures) {
    await fs.cp(e2eFixtures, target, {
      recursive: true,
      force: true,
    });
  }
}

```

--------------------------------------------------------------------------------
/packages/shared/utils/src/lib/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { CliArgsObject, ArgumentValue } from '@push-based/models';

/**
 * Converts an object with different types of values into an array of command-line arguments.
 *
 * @example
 * const args = objectToCliArgs({
 *   _: ['node', 'index.js'], // node index.js
 *   name: 'Juanita', // --name=Juanita
 *   formats: ['json', 'md'] // --format=json --format=md
 * });
 */
export function objectToCliArgs<
  T extends object = Record<string, ArgumentValue>,
>(params?: CliArgsObject<T>): string[] {
  if (!params) {
    return [];
  }

  return Object.entries(params).flatMap(([key, value]) => {
    // process/file/script
    if (key === '_') {
      return Array.isArray(value) ? value : [`${value}`];
    }
    const prefix = key.length === 1 ? '-' : '--';
    // "-*" arguments (shorthands)
    if (Array.isArray(value)) {
      return value.map((v) => `${prefix}${key}="${v}"`);
    }
    // "--*" arguments ==========

    if (Array.isArray(value)) {
      return value.map((v) => `${prefix}${key}="${v}"`);
    }

    if (typeof value === 'object') {
      return Object.entries(value as Record<string, ArgumentValue>).flatMap(
        // transform nested objects to the dot notation `key.subkey`
        ([k, v]) => objectToCliArgs({ [`${key}.${k}`]: v }),
      );
    }

    if (typeof value === 'string') {
      return [`${prefix}${key}="${value}"`];
    }

    if (typeof value === 'number') {
      return [`${prefix}${key}=${value}`];
    }

    if (typeof value === 'boolean') {
      return [`${prefix}${value ? '' : 'no-'}${key}`];
    }

    throw new Error(`Unsupported type ${typeof value} for key ${key}`);
  });
}

export function calcDuration(start: number, stop?: number): number {
  return Math.round((stop ?? performance.now()) - start);
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/report-violations/report-violations.tool.ts:
--------------------------------------------------------------------------------

```typescript
import {
  createHandler,
  BaseHandlerOptions,
  RESULT_FORMATTERS,
} from '../shared/utils/handler-helpers.js';
import {
  createViolationReportingSchema,
  COMMON_ANNOTATIONS,
} from '../shared/models/schema-helpers.js';
import { analyzeViolationsBase } from '../shared/violation-analysis/base-analyzer.js';
import { formatViolations } from '../shared/violation-analysis/formatters.js';
import { ViolationResult } from './models/types.js';

interface ReportViolationsOptions extends BaseHandlerOptions {
  directory: string;
  componentName: string;
  groupBy?: 'file' | 'folder';
}

export const reportViolationsSchema = {
  name: 'report-violations',
  description: `Report deprecated DS CSS usage in a directory with configurable grouping format.`,
  inputSchema: createViolationReportingSchema(),
  annotations: {
    title: 'Report Violations',
    ...COMMON_ANNOTATIONS.readOnly,
  },
};

export const reportViolationsHandler = createHandler<
  ReportViolationsOptions,
  string[]
>(
  reportViolationsSchema.name,
  async (params) => {
    // Default to 'file' grouping if not specified
    const groupBy = params.groupBy || 'file';

    const result = await analyzeViolationsBase<ViolationResult>(params);

    const formattedContent = formatViolations(result, params.directory, {
      groupBy,
    });

    // Extract text content from the formatted violations
    const violationLines = formattedContent.map((item) => {
      if (item.type === 'text') {
        return item.text;
      }
      return String(item);
    });

    return violationLines;
  },
  (result) => RESULT_FORMATTERS.list(result, 'Design System Violations:'),
);

export const reportViolationsTools = [
  {
    schema: reportViolationsSchema,
    handler: reportViolationsHandler,
  },
];

```

--------------------------------------------------------------------------------
/packages/shared/typescript-ast-utils/ai/API.md:
--------------------------------------------------------------------------------

```markdown
# TypeScript AST Utils

Comprehensive **TypeScript AST manipulation utilities** for working with TypeScript compiler API decorators, nodes, and source file analysis.

## Minimal usage

```ts
import {
  isComponentDecorator,
  getDecorators,
  removeQuotes,
} from '@push-based/typescript-ast-utils';
import * as ts from 'typescript';

// Check if a decorator is a Component decorator
const isComponent = isComponentDecorator(decorator);

// Get all decorators from a node
const decorators = getDecorators(classNode);

// Remove quotes from a string literal node
const cleanText = removeQuotes(stringNode, sourceFile);
```

## Key Features

- **Decorator Analysis**: Utilities for identifying and working with TypeScript decorators
- **Node Inspection**: Functions to safely extract decorators from AST nodes
- **String Processing**: Tools for cleaning quoted strings from AST nodes
- **Type Guards**: Type-safe functions for checking node properties
- **Cross-Version Compatibility**: Handles different TypeScript compiler API versions

## Use Cases

- **Angular Component Analysis**: Identify `@Component` decorators in Angular applications
- **AST Traversal**: Safely navigate TypeScript abstract syntax trees
- **Code Analysis Tools**: Build static analysis tools for TypeScript codebases
- **Decorator Processing**: Extract and process decorator metadata
- **Source Code Transformation**: Clean and manipulate string literals from source files

## Documentation map

| Doc                            | What you'll find                            |
| ------------------------------ | ------------------------------------------- |
| [FUNCTIONS.md](./FUNCTIONS.md) | A–Z quick reference for every public symbol |
| [EXAMPLES.md](./EXAMPLES.md)   | Runnable scenarios with expected output     |

```

```

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/project/get-project-dependencies.tool.ts:
--------------------------------------------------------------------------------

```typescript
import { ToolSchemaOptions } from '@push-based/models';
import {
  createHandler,
  BaseHandlerOptions,
} from '../shared/utils/handler-helpers.js';
import {
  createProjectAnalysisSchema,
  COMMON_ANNOTATIONS,
} from '../shared/models/schema-helpers.js';
import { analyzeProjectDependencies } from './utils/dependencies-helpers.js';
import { validateComponentName } from '../shared/utils/component-validation.js';

interface ProjectDependenciesOptions extends BaseHandlerOptions {
  directory: string;
  componentName?: string;
  workspaceRoot?: string;
  uiRoot?: string;
}

export const getProjectDependenciesSchema: ToolSchemaOptions = {
  name: 'get-project-dependencies',
  description: `
    Analyze project dependencies and detect if library is buildable/publishable.
    Checks for peer dependencies and validates import paths for DS components.
  `,
  inputSchema: createProjectAnalysisSchema({
    componentName: {
      type: 'string',
      description:
        'Optional component name to validate import path for (e.g., DsButton)',
    },
  }),
  annotations: {
    title: 'Get Project Dependencies',
    ...COMMON_ANNOTATIONS.readOnly,
  },
};

export const getProjectDependenciesHandler = createHandler<
  ProjectDependenciesOptions,
  any
>(
  getProjectDependenciesSchema.name,
  async (params, { cwd, workspaceRoot, uiRoot }) => {
    const { directory, componentName } = params;

    if (componentName) {
      validateComponentName(componentName);
    }

    return await analyzeProjectDependencies(
      cwd,
      directory,
      componentName,
      workspaceRoot,
      uiRoot,
    );
  },
  (result) => [JSON.stringify(result, null, 2)],
);

export const getProjectDependenciesTools = [
  {
    schema: getProjectDependenciesSchema,
    handler: getProjectDependenciesHandler,
  },
];

```

--------------------------------------------------------------------------------
/packages/shared/utils/src/lib/format-command-log.integration.test.ts:
--------------------------------------------------------------------------------

```typescript
import path from 'node:path';
import { describe, expect, it } from 'vitest';
import { removeColorCodes } from '@push-based/testing-utils';
import { formatCommandLog } from './format-command-log.js';

describe('formatCommandLog', () => {
  it('should format simple command', () => {
    const result = removeColorCodes(
      formatCommandLog('npx', ['command', '--verbose']),
    );

    expect(result).toBe('$ npx command --verbose');
  });

  it('should format simple command with explicit process.cwd()', () => {
    const result = removeColorCodes(
      formatCommandLog('npx', ['command', '--verbose'], process.cwd()),
    );

    expect(result).toBe('$ npx command --verbose');
  });

  it('should format simple command with relative cwd', () => {
    const result = removeColorCodes(
      formatCommandLog('npx', ['command', '--verbose'], './wololo'),
    );

    expect(result).toBe(`wololo $ npx command --verbose`);
  });

  it('should format simple command with absolute non-current path converted to relative', () => {
    const result = removeColorCodes(
      formatCommandLog(
        'npx',
        ['command', '--verbose'],
        path.join(process.cwd(), 'tmp'),
      ),
    );
    expect(result).toBe('tmp $ npx command --verbose');
  });

  it('should format simple command with relative cwd in parent folder', () => {
    const result = removeColorCodes(
      formatCommandLog('npx', ['command', '--verbose'], '..'),
    );

    expect(result).toBe(`.. $ npx command --verbose`);
  });

  it('should format simple command using relative path to parent directory', () => {
    const result = removeColorCodes(
      formatCommandLog(
        'npx',
        ['command', '--verbose'],
        path.dirname(process.cwd()),
      ),
    );

    expect(result).toBe('.. $ npx command --verbose');
  });
});

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-3/lazy-loader-3.component.ts:
--------------------------------------------------------------------------------

```typescript
import {
  Component,
  ViewContainerRef,
  ComponentRef,
  OnInit,
} from '@angular/core';

@Component({
  selector: 'app-lazy-loader',
  template: `
    <div>
      <h2>Lazy Component Loader</h2>
      <button (click)="loadComponent()" [disabled]="isLoading">
        {{ isLoading ? 'Loading...' : 'Load External Assets Component' }}
      </button>
      <div #dynamicContainer></div>
    </div>
  `,
  styles: [
    `
      button {
        padding: 10px 20px;
        margin: 10px 0;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }
      button:disabled {
        background-color: #6c757d;
        cursor: not-allowed;
      }
    `,
  ],
})
export class LazyLoaderComponent3 implements OnInit {
  isLoading = false;
  private componentRef?: ComponentRef<any>;

  constructor(private viewContainerRef: ViewContainerRef) {}

  ngOnInit() {
    console.log('LazyLoaderComponent initialized');
  }

  async loadComponent() {
    if (this.isLoading || this.componentRef) {
      return;
    }

    this.isLoading = true;

    try {
      // Dynamic import statement - this is the key part for lazy loading
      const { BadMixedExternalAssetsComponent3 } = await import(
        './bad-mixed-external-assets-3.component'
      );

      // Clear the container
      this.viewContainerRef.clear();

      // Create the component dynamically
      this.componentRef = this.viewContainerRef.createComponent(
        BadMixedExternalAssetsComponent3
      );

      console.log('Component loaded successfully');
    } catch (error) {
      console.error('Failed to load component:', error);
    } finally {
      this.isLoading = false;
    }
  }

  ngOnDestroy() {
    if (this.componentRef) {
      this.componentRef.destroy();
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/src/lib/decorator-config.visitor.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { classDecoratorVisitor } from './decorator-config.visitor.js';
import * as ts from 'typescript';

describe('DecoratorConfigVisitor', () => {
  it.skip('should not find class when it is not a class-binding', async () => {
    const sourceCode = `
  class Example {
    method() {}
  }

  function greet() {
    console.log('Hello');
  }

  let x = 123;
`;

    const sourceFile = ts.createSourceFile(
      'example.ts',
      sourceCode,
      ts.ScriptTarget.Latest,
      true,
    );

    const visitor = await classDecoratorVisitor({ sourceFile });
    ts.visitEachChild(sourceFile, visitor, undefined);

    expect(visitor.components).toEqual([]);
  });

  it('should not find class when it is not a class-binding', async () => {
    const sourceCode = `
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'minimal';
}
`;

    const sourceFile = ts.createSourceFile(
      'example.ts',
      sourceCode,
      ts.ScriptTarget.Latest,
      true,
    );
    const visitor = await classDecoratorVisitor({ sourceFile });

    ts.visitEachChild(sourceFile, visitor, undefined);

    expect(visitor.components).toStrictEqual([
      expect.objectContaining({
        className: 'AppComponent',
        fileName: 'example.ts',
        startLine: 4,
        selector: 'app-root',
        imports: '[RouterOutlet]',
        styleUrls: [
          expect.objectContaining({
            startLine: 8,
            filePath: 'example.ts',
          }),
        ],
        templateUrl: expect.objectContaining({
          startLine: 7,
          filePath: 'example.ts',
        }),
      }),
    ]);
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/validation/ds-components-file.validation.ts:
--------------------------------------------------------------------------------

```typescript
import * as path from 'path';
import { AngularMcpServerOptions } from './angular-mcp-server-options.schema.js';
import { DsComponentsArraySchema } from './ds-components.schema.js';
import { loadDefaultExport } from '@push-based/utils';

export async function validateDeprecatedCssClassesFile(
  config: AngularMcpServerOptions,
): Promise<void> {
  const relPath = config.ds.deprecatedCssClassesPath;
  if (!relPath) {
    // Optional parameter not provided; nothing to validate
    return;
  }
  const deprecatedCssClassesAbsPath = path.resolve(
    config.workspaceRoot,
    relPath,
  );

  const dsComponents = await loadDefaultExport(deprecatedCssClassesAbsPath);

  const validation = DsComponentsArraySchema.safeParse(dsComponents);
  if (!validation.success) {
    const actualType = Array.isArray(dsComponents)
      ? 'array'
      : typeof dsComponents;
    const exportedValue =
      dsComponents === undefined
        ? 'undefined'
        : dsComponents === null
          ? 'null'
          : JSON.stringify(dsComponents, null, 2).substring(0, 100) +
            (JSON.stringify(dsComponents).length > 100 ? '...' : '');

    throw new Error(
      `Invalid deprecated CSS classes configuration format in: ${deprecatedCssClassesAbsPath}\n\n` +
        `Expected: Array of component objects\n` +
        `Received: ${actualType}\n` +
        `Value: ${exportedValue}\n\n` +
        `Fix options:\n` +
        `1. ES Module format:\n` +
        `   export default [\n` +
        `     { componentName: 'DsButton', deprecatedCssClasses: ['btn'] }\n` +
        `   ];\n\n` +
        `2. CommonJS format:\n` +
        `   module.exports = {\n` +
        `     dsComponents: [{ componentName: 'DsButton', deprecatedCssClasses: ['btn'] }]\n` +
        `   };\n\n` +
        `Schema errors: ${JSON.stringify(validation.error.format(), null, 2)}`,
    );
  }
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-mixed.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesComponent {}

```

--------------------------------------------------------------------------------
/packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/sub-folder-1/sub-folder-2/bad-mixed.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesComponent {}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-1/bad-mixed-1.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesComponent1 {}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-2/bad-mixed-2.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesComponent2 {}

```

--------------------------------------------------------------------------------
/packages/shared/styles-ast-utils/src/lib/stylesheet.walk.ts:
--------------------------------------------------------------------------------

```typescript
import { Root, Rule } from 'postcss';

import { CssAstVisitor } from './stylesheet.visitor.js';
import { NodeType } from './types.js';

/**
 * Single function that traverses the AST, calling
 * specialized visitor methods as it encounters each node type.
 */
export function visitEachChild<T>(root: Root, visitor: CssAstVisitor<T>) {
  visitor.visitRoot?.(root);

  root.walk((node) => {
    const visitMethodName = `visit${
      node.type[0].toUpperCase() + node.type.slice(1)
    }` as keyof CssAstVisitor<T>;
    const visitMethod = visitor[visitMethodName] as
      | ((node: NodeType<typeof visitMethodName>) => void)
      | undefined;
    visitMethod?.(node as NodeType<typeof visitMethodName>);
  });
}

export function visitStyleSheet<T>(root: Root, visitor: CssAstVisitor<T>) {
  for (const node of root.nodes) {
    switch (node.type) {
      case 'rule':
        visitor?.visitRule?.(node);
        break;
      case 'atrule':
        visitor?.visitAtRule?.(node);
        break;
      case 'decl':
        throw new Error('visit declaration not implemented');
      // visitor?.visitDeclaration?.(node);
      case 'comment':
        visitor?.visitComment?.(node);
        break;
      default:
        throw new Error(`Unknown node type: ${(node as Root).type}`);
    }
  }
}

export function visitEachStyleNode<T>(
  nodes: Root['nodes'],
  visitor: CssAstVisitor<T>,
) {
  for (const node of nodes) {
    switch (node.type) {
      case 'rule':
        visitor?.visitRule?.(node);
        visitEachStyleNode((node as Rule).nodes, visitor);
        break;
      case 'atrule':
        visitor?.visitAtRule?.(node);
        break;
      case 'decl':
        visitor?.visitDecl?.(node);
        break;
      case 'comment':
        visitor?.visitComment?.(node);
        break;
      default:
        throw new Error(`Unknown node type: ${(node as Root).type}`);
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/utils/inline-styles.collector.ts:
--------------------------------------------------------------------------------

```typescript
import { parseStylesheet, visitEachChild } from '@push-based/styles-ast-utils';
import { selectorMatches } from './css-match.js';
import type {
  StyleDeclarations,
  DomStructure,
} from '../../shared/models/types.js';
import type { Declaration, Rule } from 'postcss';
import type { ParsedComponent } from '@push-based/angular-ast-utils';

/**
 * Collect style rules declared inline via the `styles` property of an
 * `@Component` decorator and map them to the DOM snapshot that comes from the
 * template.
 */
export async function collectInlineStyles(
  component: ParsedComponent,
  dom: DomStructure,
): Promise<StyleDeclarations> {
  const styles: StyleDeclarations = {
    // Inline styles logically live in the component TS file
    sourceFile: component.fileName,
    rules: {},
  };

  if (!component.styles || component.styles.length === 0) {
    return styles;
  }

  // Combine all inline style strings into one CSS blob
  const cssText = (
    await Promise.all(component.styles.map((asset) => asset.parse()))
  )
    .map((root) => root.toString())
    .join('\n');

  if (!cssText.trim()) {
    return styles;
  }

  const parsed = parseStylesheet(cssText, component.fileName);
  if (parsed.root.type !== 'root') {
    return styles;
  }

  visitEachChild(parsed.root, {
    visitRule: (rule: Rule) => {
      const properties: Record<string, string> = {};

      rule.walkDecls?.((decl: Declaration) => {
        properties[decl.prop] = decl.value;
      });

      styles.rules[rule.selector] = {
        appliesTo: findMatchingDomElements(rule.selector, dom),
        properties,
      };
    },
  });

  return styles;
}

function findMatchingDomElements(
  cssSelector: string,
  dom: DomStructure,
): string[] {
  return Object.entries(dom)
    .filter(([domKey, element]) =>
      selectorMatches(cssSelector, domKey, element),
    )
    .map(([domKey]) => domKey);
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-mixed-not-standalone.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  standalone: false,
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesNotStandaloneComponent {}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-1/bad-mixed-not-standalone-1.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  standalone: false,
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesNotStandaloneComponent1 {}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-2/bad-mixed-not-standalone-2.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  standalone: false,
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesNotStandaloneComponent2 {}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-3/bad-mixed-not-standalone-3.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  standalone: false,
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesNotStandaloneComponent3 {}

```

--------------------------------------------------------------------------------
/nx.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/.eslintrc.json",
      "!{projectRoot}/eslint.config.mjs",
      "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
      "!{projectRoot}/tsconfig.spec.json",
      "!{projectRoot}/jest.config.[jt]s",
      "!{projectRoot}/src/test-setup.[jt]s",
      "!{projectRoot}/test-setup.[jt]s"
    ],
    "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"]
  },
  "plugins": [
    {
      "plugin": "@nx/js/typescript",
      "options": {
        "typecheck": {
          "targetName": "typecheck"
        },
        "build": {
          "targetName": "build",
          "configName": "tsconfig.lib.json",
          "buildDepsName": "build-deps",
          "watchDepsName": "watch-deps"
        }
      }
    },
    {
      "plugin": "@nx/webpack/plugin",
      "options": {
        "buildTargetName": "build",
        "serveTargetName": "serve",
        "previewTargetName": "preview",
        "buildDepsTargetName": "build-deps",
        "watchDepsTargetName": "watch-deps"
      }
    },
    {
      "plugin": "@nx/eslint/plugin",
      "options": {
        "targetName": "lint"
      }
    },
    {
      "plugin": "@nx/vite/plugin",
      "options": {
        "buildTargetName": "build",
        "testTargetName": "test",
        "serveTargetName": "serve",
        "devTargetName": "dev",
        "previewTargetName": "preview",
        "serveStaticTargetName": "serve-static",
        "typecheckTargetName": "typecheck",
        "buildDepsTargetName": "build-deps",
        "watchDepsTargetName": "watch-deps"
      }
    }
  ],
  "targetDefaults": {
    "@nx/js:swc": {
      "cache": true,
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"]
    },
    "test": {
      "dependsOn": ["^build"]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/storybook-host-app/src/components/modal/modal-tabs/api.mdx:
--------------------------------------------------------------------------------

```markdown
## Inputs

### `ds-modal-header`

| Name      | Type                                                               | Default     | Description                           |
| --------- | ------------------------------------------------------------------ | ----------- | ------------------------------------- |
| `variant` | `'surface-lowest' \| 'surface-low' \| 'surface' \| 'surface-high'` | `'surface'` | Background style for the modal header |

Other components (`ds-modal`, `ds-modal-content`, `ds-modal-header-drag`) do not define any `@Input()` bindings.

---

## Outputs

None of the modal-related components emit Angular `@Output()` events.

---

## Content Projection

### `ds-modal`

Supports default slot:

```html
<ds-modal>
  <ds-modal-header>...</ds-modal-header>
  <ds-modal-content>...</ds-modal-content>
</ds-modal>
```

### `ds-modal-header`

Defines multiple named slots:

```html
<ds-modal-header>
  <span slot="start">Back</span>
  <div slot="center">Title</div>
  <button slot="end">Close</button>
</ds-modal-header>
```

Content is rendered into:

- `[slot=start]` → left section
- `[slot=center]` → center section
- `ds-modal-header-drag`, `[modal-header-image]` → center below title
- `[slot=end]` → right section

### `ds-modal-content`

Projects content as modal body:

```html
<ds-modal-content> Modal text goes here. </ds-modal-content>
```

---

## Host Element Behavior

### `ds-modal`

- Host class: `ds-modal`
- Attributes:
- `role="dialog"`
- `aria-label="Modal dialog"`

### `ds-modal-header`

- Host class: `ds-modal-header`
- Dynamic class based on `variant`: `ds-modal-header-surface`, `ds-modal-header-surface-low`, etc.
- Attributes:
- `role="dialog"`
- `aria-label="Modal header dialog"`

### `ds-modal-header-drag`

- Host class: `ds-modal-header-drag`
- Attributes:
- `role="dialog"`
- `aria-label="Modal header drag dialog"`

### `ds-modal-content`

- Host class: `ds-modal-content`
- No interactive attributes applied

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-3/bad-mixed-3.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

@Component({
  selector: 'app-mixed-styles',
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <!-- ✅ Good: Using DSButton -->
    <ds-button>Good Button</ds-button>

    <!-- ❌ Bad: Legacy button class -->
    <button class="btn btn-primary">Bad Button</button>

    <!-- ✅ Good: Using DSModal -->
    <ds-modal [open]="true">
      <p>Good Modal Content</p>
    </ds-modal>

    <!-- ❌ Bad: Custom modal with legacy styles -->
    <div class="modal">
      <div class="modal-content">
        <h2>Bad Modal</h2>
        <p>This is a legacy modal.</p>
      </div>
    </div>

    <!-- ✅ Good: DSProgressBar -->
    <ds-progress-bar [value]="50"></ds-progress-bar>

    <!-- ❌ Bad: Manually styled progress bar -->
    <div class="progress-bar">
      <div class="progress" style="width: 50%;"></div>
    </div>

    <!-- ✅ Good: DSDropdown -->
    <ds-dropdown [options]="['Option 1', 'Option 2']"></ds-dropdown>

    <!-- ❌ Bad: Legacy dropdown -->
    <select class="dropdown">
      <option>Option 1</option>
      <option>Option 2</option>
    </select>

    <!-- ✅ Good: Using DSAlert -->
    <ds-alert type="error"> Good Alert </ds-alert>

    <!-- ❌ Bad: Manually styled alert -->
    <div class="alert alert-danger">Bad Alert</div>

    <!-- ✅ Good: Using DSTooltip -->
    <ds-tooltip content="Good tooltip">Hover me</ds-tooltip>

    <!-- ❌ Bad: Legacy tooltip -->
    <div class="tooltip">Bad tooltip</div>

    <!-- ✅ Good: Using DSBreadcrumb -->
    <ds-breadcrumb>
      <ds-breadcrumb-item>Home</ds-breadcrumb-item>
      <ds-breadcrumb-item>Products</ds-breadcrumb-item>
      <ds-breadcrumb-item>Details</ds-breadcrumb-item>
    </ds-breadcrumb>

    <!-- ❌ Bad: Manually created breadcrumb -->
    <nav class="breadcrumb">
      <span>Home</span> / <span>Products</span> / <span>Details</span>
    </nav>
  `,
})
export class MixedStylesComponent3 {}

```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/ai/EXAMPLES.md:
--------------------------------------------------------------------------------

```markdown
# Examples

## 1 — Parsing components

> Parse a single Angular component file and list component class names.

```ts
import { parseComponents } from 'angular-ast-utils';

const comps = await parseComponents(['src/app/app.component.ts']);
console.log(comps.map((c) => c.className));
```

---

## 2 — Checking for a CSS class

> Detect whether a given class name appears in an Angular `[ngClass]` binding.

```ts
import { ngClassesIncludeClassName } from 'angular-ast-utils';

const source = "{'btn' : isActive}";
const hasBtn = ngClassesIncludeClassName(source, 'btn');
console.log(hasBtn); // → true
```

---

## 3 — Finding Angular units by type

> Find all components, directives, pipes, or services in a directory.

```ts
import { findAngularUnits } from 'angular-ast-utils';

const componentFiles = await findAngularUnits('./src/app', 'component');
const serviceFiles = await findAngularUnits('./src/app', 'service');
console.log(componentFiles); // → ['./src/app/app.component.ts', ...]
```

---

## 4 — Parsing Angular units in a directory

> Parse all Angular components in a directory and get their metadata.

```ts
import { parseAngularUnit } from 'angular-ast-utils';

const components = await parseAngularUnit('./src/app', 'component');
console.log(components.map((c) => c.className)); // → ['AppComponent', ...]
```

---

## 5 — Visiting component templates

> Run a visitor function against a component's template AST.

```ts
import { visitComponentTemplate } from 'angular-ast-utils';

await visitComponentTemplate(component, searchTerm, async (term, template) => {
  // Process template AST and return issues
  return [];
});
```

---

## 6 — Visiting component styles

> Run a visitor function against a component's styles.

```ts
import { visitComponentStyles } from 'angular-ast-utils';

const issues = await visitComponentStyles(
  component,
  searchTerm,
  async (term, style) => {
    // Process style AST and return issues
    return [];
  }
);
```

```

--------------------------------------------------------------------------------
/packages/shared/styles-ast-utils/src/lib/utils.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect } from 'vitest';
import { parseStylesheet } from './stylesheet.parse';
import { Rule } from 'postcss';
import { styleAstRuleToSource } from './utils';

describe('styleAstRuleToSource', () => {
  it('should have line number starting from 1', () => {
    const result = parseStylesheet(`.btn{ color: red; }`, 'inline-styles').root;
    const source = styleAstRuleToSource(result?.nodes?.at(0) as Rule);
    expect(source).toStrictEqual({
      file: expect.stringMatching(/inline-styles$/),
      position: {
        startLine: 1,
        startColumn: 1,
        endLine: 1,
        endColumn: 19,
      },
    });
  });

  it('should have line number where startLine is respected', () => {
    const result = parseStylesheet(`.btn{ color: red; }`, 'styles.css').root;
    const source = styleAstRuleToSource(result?.nodes?.at(0) as Rule, 4);
    expect(source).toStrictEqual({
      file: expect.stringMatching(/styles\.css$/),
      position: {
        startLine: 5,
        startColumn: 1,
        endLine: 5,
        endColumn: 19,
      },
    });
  });

  it('should have correct line number for starting line breaks', () => {
    const result = parseStylesheet(
      `

.btn{ color: red; }`,
      'styles.css',
    ).root;
    const source = styleAstRuleToSource(result?.nodes?.at(0) as Rule);
    expect(source).toStrictEqual({
      file: expect.stringMatching(/styles\.css$/),
      position: {
        startLine: 3,
        startColumn: 1,
        endLine: 3,
        endColumn: 19,
      },
    });
  });

  it('should have correct line number for spans', () => {
    const result = parseStylesheet(
      `
.btn{
  color: red;
}`,
      'styles.css',
    ).root;

    const source = styleAstRuleToSource(result?.nodes?.at(0) as Rule);
    expect(source).toStrictEqual({
      file: expect.stringMatching(/styles\.css$/),
      position: {
        startLine: 2,
        startColumn: 1,
        endLine: 4,
        endColumn: 1,
      },
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@push-based/angular-toolkit-mcp",
  "version": "0.2.0",
  "description": "A Model Context Protocol server for Angular project analysis and refactoring",
  "keywords": [
    "mcp",
    "angular",
    "refactoring",
    "analysis",
    "model-context-protocol"
  ],
  "author": "Push-Based",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/push-based/angular-toolkit-mcp.git"
  },
  "homepage": "https://github.com/push-based/angular-toolkit-mcp",
  "bugs": "https://github.com/push-based/angular-toolkit-mcp/issues",
  "engines": {
    "node": ">=18"
  },
  "publishConfig": {
    "access": "public"
  },
  "bin": {
    "angular-toolkit-mcp": "main.js"
  },
  "files": [
    "main.js",
    "*.js",
    "README.md"
  ],
  "nx": {
    "implicitDependencies": [
      "angular-mcp-server"
    ],
    "targets": {
      "serve": {
        "executor": "@nx/js:node",
        "defaultConfiguration": "development",
        "dependsOn": [
          "build"
        ],
        "options": {
          "buildTarget": "angular-mcp:build",
          "runBuildTargetDependencies": false
        },
        "configurations": {
          "development": {
            "buildTarget": "angular-mcp:build:development"
          },
          "production": {
            "buildTarget": "angular-mcp:build:production"
          }
        }
      },
      "serve-static": {
        "dependsOn": [
          "^build"
        ],
        "command": "node packages/angular-mcp/dist/main.js"
      },
      "debug": {
        "dependsOn": [
          "build"
        ],
        "command": "npx @modelcontextprotocol/inspector node packages/angular-mcp/dist/main.js --workspaceRoot=/root/path/to/workspace   --ds.uiRoot=packages/minimal-repo/packages/design-system/ui --ds.storybookDocsRoot=packages/minimal-repo/packages/design-system/storybook-host-app/src/components --ds.deprecatedCssClassesPath=packages/minimal-repo/packages/design-system/component-options.mjs"
      }
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/ui/segmented-control/src/segmented-control.component.html:
--------------------------------------------------------------------------------

```html
<div class="ds-segmented-control-container" #scContainer>
  <div
    class="ds-segmented-controls"
    [attr.role]="roleType()"
    [class.ds-sc-ready]="isReady()"
    [class.ds-segment-full-width]="fullWidth()"
    [class.ds-segment-inverse]="inverse()"
    (keydown)="onKeydown($event)"
  >
    @for (option of segmentedOptions(); track option.name()) {
      <div
        #tabOption
        class="ds-segment-item"
        [class.ds-segment-selected]="
          option.name() === this.selectedOption()?.name()
        "
        [id]="'ds-segment-item-' + option.name()"
        [attr.tabindex]="
          option.name() === this.selectedOption()?.name() ? 0 : -1
        "
        [attr.role]="roleType() === 'tablist' ? 'tab' : 'radio'"
        [attr.aria-selected]="
          roleType() === 'tablist'
            ? option.name() === this.selectedOption()?.name()
              ? 'true'
              : 'false'
            : null
        "
        [attr.aria-checked]="
          roleType() === 'radiogroup'
            ? option.name() === this.selectedOption()?.name()
              ? 'true'
              : 'false'
            : null
        "
        [attr.aria-label]="option.title() || option.name()"
        (click)="selectOption(option.name(), $event)"
      >
        <input
          type="radio"
          class="ds-segmented-control-hidden-input"
          [value]="option.name()"
          [name]="option.name()"
          [id]="'ds-sc-option-' + option.name()"
          [checked]="option.selected()"
          [attr.aria-labelledby]="'ds-segment-item-' + option.name()"
          [title]="option.title()"
        />
        <label
          class="ds-segment-item-label"
          [for]="'ds-sc-option-' + option.title()"
          [class.ds-segmented-item-two-line-text]="twoLineTruncation()"
          [class.ds-segment-item-custom-template]="option.customTemplate()"
        >
          @if (option.customTemplate()) {
            <ng-container [ngTemplateOutlet]="option.customTemplate()!" />
          } @else {
            {{ option.title() }}
          }
        </label>
      </div>
    }
  </div>
</div>

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/diff/spec/dom-path-utils.spec.ts:
--------------------------------------------------------------------------------

```typescript
/* eslint-disable prefer-const */
import { describe, it, expect } from 'vitest';

import {
  createDomPathDictionary,
  isDomPath,
  isValidDomPath,
  addDomPath,
  processDomPaths,
} from '../utils/dom-path-utils.js';

const SAMPLE_PATH = 'div#root > span.foo > button.bar';

describe('dom-path-utils', () => {
  describe('isDomPath / isValidDomPath', () => {
    it('detects DOM-like selector strings correctly', () => {
      expect(isDomPath(SAMPLE_PATH)).toBe(true);
      expect(isValidDomPath(SAMPLE_PATH)).toBe(true);

      expect(isDomPath('div')).toBe(false);
      expect(isDomPath('div.foo')).toBe(false);
      const mediaPath = `${SAMPLE_PATH} @media`;
      expect(isDomPath(mediaPath)).toBe(true);
      expect(isValidDomPath(mediaPath)).toBe(false);
    });
  });

  describe('addDomPath & createDomPathDictionary', () => {
    it('adds new paths and deduplicates existing ones', () => {
      const dict = createDomPathDictionary();

      const ref1 = addDomPath(dict, SAMPLE_PATH);
      expect(ref1).toEqual({ $domPath: 0 });
      expect(dict.paths[0]).toBe(SAMPLE_PATH);
      expect(dict.stats.totalPaths).toBe(1);
      expect(dict.stats.uniquePaths).toBe(1);
      expect(dict.stats.duplicateReferences).toBe(0);

      const ref2 = addDomPath(dict, SAMPLE_PATH);
      expect(ref2).toEqual({ $domPath: 0 });
      expect(dict.stats.totalPaths).toBe(2);
      expect(dict.stats.uniquePaths).toBe(1);
      expect(dict.stats.duplicateReferences).toBe(1);
    });
  });

  describe('processDomPaths', () => {
    it('recursively replaces DOM path strings with references', () => {
      const dict = createDomPathDictionary();

      const input = {
        pathA: SAMPLE_PATH,
        nested: ['no-dom-path', SAMPLE_PATH, { deeper: SAMPLE_PATH }],
      };

      const processed = processDomPaths(input, dict);

      expect(processed.pathA).toEqual({ $domPath: 0 });
      expect(processed.nested[1]).toEqual({ $domPath: 0 });
      expect(processed.nested[2].deeper).toEqual({ $domPath: 0 });

      expect(dict.paths).toEqual([SAMPLE_PATH]);
      expect(dict.stats.uniquePaths).toBe(1);
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/app.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { BadAlertComponent } from './components/refactoring-tests/bad-alert.component';
import { BadAlertTooltipInputComponent } from './components/refactoring-tests/bad-alert-tooltip-input.component';
import { BadButtonDropdownComponent } from './components/refactoring-tests/bad-button-dropdown.component';
import { MixedStylesComponent } from './components/refactoring-tests/bad-mixed.component';
import { BadModalProgressComponent } from './components/refactoring-tests/bad-modal-progress.component';
import { BadMixedExternalAssetsComponent } from './components/refactoring-tests/bad-mixed-external-assets.component';
import { BadDocumentComponent } from './components/refactoring-tests/bad-document.component';
import { BadWindowComponent } from './components/refactoring-tests/bad-window.component';
import { BadThisWindowDocumentComponent } from './components/refactoring-tests/bad-this-window-document.component';
import { BadGlobalThisComponent } from './components/refactoring-tests/bad-global-this.component';

@Component({
  selector: 'app-root',
  imports: [
    RouterOutlet,
    BadAlertComponent,
    BadAlertTooltipInputComponent,
    BadModalProgressComponent,
    BadButtonDropdownComponent,
    MixedStylesComponent,
    BadMixedExternalAssetsComponent,
    BadDocumentComponent,
    BadGlobalThisComponent,
    BadWindowComponent,
    BadThisWindowDocumentComponent,
  ],
  template: `
    <h1>{{ title }}</h1>
    <button class="btn">Sports</button>
    <app-bad-alert></app-bad-alert>
    <app-bad-alert-tooltip-input></app-bad-alert-tooltip-input>
    <app-bad-modal-progress></app-bad-modal-progress>
    <app-mixed-styles></app-mixed-styles>
    <app-bad-button-dropdown></app-bad-button-dropdown>
    <app-bad-mixed-external-assets></app-bad-mixed-external-assets>
    <app-bad-window></app-bad-window>
    <app-bad-this-window-document></app-bad-this-window-document>
    <app-bad-document></app-bad-document>
    <app-bad-global-this></app-bad-global-this>
    <router-outlet />
  `,
})
export class AppComponent {
  title = 'minimal';
}

```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/src/lib/template/noop-tmpl-visitor.ts:
--------------------------------------------------------------------------------

```typescript
import type {
  TmplAstVisitor,
  TmplAstElement,
  TmplAstTemplate,
  TmplAstContent,
  TmplAstText,
  TmplAstBoundText,
  TmplAstIcu,
  TmplAstReference,
  TmplAstVariable,
  TmplAstBoundEvent,
  TmplAstBoundAttribute,
  TmplAstTextAttribute,
  TmplAstUnknownBlock,
  TmplAstDeferredBlock,
  TmplAstDeferredBlockError,
  TmplAstDeferredBlockLoading,
  TmplAstDeferredBlockPlaceholder,
  TmplAstDeferredTrigger,
  TmplAstIfBlock,
  TmplAstIfBlockBranch,
  TmplAstSwitchBlock,
  TmplAstSwitchBlockCase,
  TmplAstForLoopBlock,
  TmplAstForLoopBlockEmpty,
  TmplAstLetDeclaration,
} from '@angular/compiler' with { 'resolution-mode': 'import' };

/**
 * Base visitor that does nothing.
 * Extend this in concrete visitors so you only override what you need.
 */
export abstract class NoopTmplVisitor implements TmplAstVisitor<void> {
  /* eslint-disable @typescript-eslint/no-empty-function */
  visitElement(_: TmplAstElement): void {}
  visitTemplate(_: TmplAstTemplate): void {}
  visitContent(_: TmplAstContent): void {}
  visitText(_: TmplAstText): void {}
  visitBoundText(_: TmplAstBoundText): void {}
  visitIcu(_: TmplAstIcu): void {}
  visitReference(_: TmplAstReference): void {}
  visitVariable(_: TmplAstVariable): void {}
  visitBoundEvent(_: TmplAstBoundEvent): void {}
  visitBoundAttribute(_: TmplAstBoundAttribute): void {}
  visitTextAttribute(_: TmplAstTextAttribute): void {}
  visitUnknownBlock(_: TmplAstUnknownBlock): void {}
  visitDeferredBlock(_: TmplAstDeferredBlock): void {}
  visitDeferredBlockError(_: TmplAstDeferredBlockError): void {}
  visitDeferredBlockLoading(_: TmplAstDeferredBlockLoading): void {}
  visitDeferredBlockPlaceholder(_: TmplAstDeferredBlockPlaceholder): void {}
  visitDeferredTrigger(_: TmplAstDeferredTrigger): void {}
  visitIfBlock(_: TmplAstIfBlock): void {}
  visitIfBlockBranch(_: TmplAstIfBlockBranch): void {}
  visitSwitchBlock(_: TmplAstSwitchBlock): void {}
  visitSwitchBlockCase(_: TmplAstSwitchBlockCase): void {}
  visitForLoopBlock(_: TmplAstForLoopBlock): void {}
  visitForLoopBlockEmpty(_: TmplAstForLoopBlockEmpty): void {}
  visitLetDeclaration(_: TmplAstLetDeclaration): void {}
  /* eslint-enable */
}

```

--------------------------------------------------------------------------------
/docs/getting-started.md:
--------------------------------------------------------------------------------

```markdown
# Getting Started with Angular MCP Toolkit

A concise, hands-on guide to install, configure, and verify the Angular MCP server in under **5 minutes**.

---

## 1. Prerequisites

| Tool | Minimum Version | Notes |
| ---- | --------------- | ----- |
| Node.js | **18.x** LTS | Tested with 18.18 ⬆︎ |
| npm | **9.x** | Bundled with Node LTS |
| Nx CLI | **≥ 21** | `npm i -g nx` |
| Git | Any recent | For workspace cloning |

> The server itself is framework-agnostic, but most built-in tools assume an **Nx workspace** with Angular projects.

---

## 2. Install the Server

### Clone the repository

```bash
git clone https://github.com/push-based/angular-toolkit-mcp.git
cd angular-toolkit-mcp
npm install   # install workspace dependencies
```

The MCP server source resides under `packages/angular-mcp/` and `packages/angular-mcp-server/`. No package needs to be fetched from the npm registry.

---

## 3. Register with Your Editor

Instead of the palette-based flow, copy the manual configuration from your workspace’s `.cursor/mcp.json` (shown below) and adjust paths if necessary.

```json
{
  "mcpServers": {
    "angular-mcp": {
      "command": "node",
      "args": [
        "./packages/angular-mcp/dist/main.js",
        "--workspaceRoot=/absolute/path/to/angular-toolkit-mcp",
        "--ds.storybookDocsRoot=packages/minimal-repo/packages/design-system/storybook-host-app/src/components",
        "--ds.deprecatedCssClassesPath=packages/minimal-repo/packages/design-system/component-options.mjs",
        "--ds.uiRoot=packages/minimal-repo/packages/design-system/ui"
      ]
    }
  }
}
```

Add or edit this JSON in **Cursor → Settings → MCP Servers** (or the equivalent dialog in your editor).

---

## 4. Next Steps

🔗 Continue with the [Architecture & Internal Design](./architecture-internal-design.md) document (work-in-progress).

🚀 Jump straight into [Writing Custom Tools](./writing-custom-tools.md) when ready.

---

## Troubleshooting

| Symptom | Possible Cause | Fix |
| ------- | -------------- | --- |
| `command not found: nx` | Nx CLI missing | `npm i -g nx` |
| Editor shows “tool not found” | Server not running or wrong path in `mcp.json` | Check configuration and restart editor |

---

*Happy coding!* ✨ 
```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/diff/utils/dom-path-utils.ts:
--------------------------------------------------------------------------------

```typescript
import type { DomPathDictionary } from '../../shared/models/types.js';

/**
 * Creates a new DOM path dictionary
 */
export function createDomPathDictionary(): DomPathDictionary {
  return {
    paths: [],
    lookup: new Map<string, number>(),
    stats: {
      totalPaths: 0,
      uniquePaths: 0,
      duplicateReferences: 0,
      bytesBeforeDeduplication: 0,
      bytesAfterDeduplication: 0,
    },
  };
}

/**
 * Detects if a string is a DOM path based on Angular component patterns
 */
export function isDomPath(str: string): boolean {
  return (
    typeof str === 'string' &&
    str.length > 20 &&
    str.includes(' > ') &&
    (str.includes('.') || str.includes('#')) &&
    /^[a-zA-Z]/.test(str)
  );
}

/**
 * Validates that a string is specifically a DOM path and not just any CSS selector
 */
export function isValidDomPath(str: string): boolean {
  return (
    isDomPath(str) &&
    !str.includes('@media') &&
    !str.includes('{') &&
    !str.includes('}') &&
    str.split(' > ').length > 2
  );
}

/**
 * Adds a DOM path to the dictionary and returns its reference
 */
export function addDomPath(
  dict: DomPathDictionary,
  path: string,
): { $domPath: number } {
  dict.stats.totalPaths++;
  dict.stats.bytesBeforeDeduplication += path.length;

  if (dict.lookup.has(path)) {
    dict.stats.duplicateReferences++;
    dict.stats.bytesAfterDeduplication += 12;
    return { $domPath: dict.lookup.get(path)! };
  }

  const index = dict.paths.length;
  dict.paths.push(path);
  dict.lookup.set(path, index);
  dict.stats.uniquePaths++;
  dict.stats.bytesAfterDeduplication += 12;

  return { $domPath: index };
}

/**
 * Processes a value and replaces DOM paths with references
 */
export function processDomPaths(value: any, dict: DomPathDictionary): any {
  if (typeof value === 'string') {
    if (isValidDomPath(value)) {
      return addDomPath(dict, value);
    }
    return value;
  }

  if (Array.isArray(value)) {
    return value.map((item) => processDomPaths(item, dict));
  }

  if (value && typeof value === 'object') {
    const processed: any = {};
    for (const [key, val] of Object.entries(value)) {
      processed[key] = processDomPaths(val, dict);
    }
    return processed;
  }

  return value;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/ui/badge/src/badge.component.ts:
--------------------------------------------------------------------------------

```typescript
import {
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  ViewEncapsulation,
  booleanAttribute,
  computed,
  input,
} from '@angular/core';

export const DS_BADGE_VARIANT_ARRAY = [
  'primary',
  'primary-strong',
  'primary-subtle',
  'secondary',
  'secondary-strong',
  'secondary-subtle',
  'green',
  'green-strong',
  'green-subtle',
  'blue',
  'blue-strong',
  'blue-subtle',
  'red',
  'red-strong',
  'red-subtle',
  'purple',
  'purple-strong',
  'purple-subtle',
  'neutral',
  'neutral-strong',
  'neutral-subtle',
  'yellow',
  'yellow-strong',
  'yellow-subtle',
  'orange',
  'orange-strong',
  'orange-subtle',
] as const;

export type DsBadgeVariant = (typeof DS_BADGE_VARIANT_ARRAY)[number];

export const DS_BADGE_SIZE_ARRAY = ['xsmall', 'medium'] as const;
export type DsBadgeSize = (typeof DS_BADGE_SIZE_ARRAY)[number];

@Component({
  selector: 'ds-badge',
  template: `
    <div class="ds-badge-slot-container">
      <ng-content select="[slot=start]" />
    </div>
    <span class="ds-badge-text">
      <ng-content />
    </span>
    <div class="ds-badge-slot-container">
      <ng-content select="[slot=end]" />
    </div>
  `,
  host: {
    '[class]': 'hostClass()',
    '[class.ds-badge-disabled]': 'disabled()',
    '[class.ds-badge-inverse]': 'inverse()',
    '[attr.aria-label]': 'getAriaLabel()',
    role: 'img', // for now we are using role img till we find better solution to work with nvda
  },
  standalone: true,
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DsBadge {
  size = input<DsBadgeSize>('medium');
  variant = input<DsBadgeVariant>('primary');
  disabled = input(false, { transform: booleanAttribute });
  inverse = input(false, { transform: booleanAttribute });

  hostClass = computed(
    () => `ds-badge ds-badge-${this.size()} ds-badge-${this.variant()}`,
  );

  constructor(public elementRef: ElementRef<HTMLElement>) {}

  public getAriaLabel(): string {
    const mainContent = this.elementRef.nativeElement
      .querySelector('.ds-badge-text')
      ?.textContent?.trim();

    const label = mainContent || '';

    if (this.disabled()) {
      return `Disabled badge: ${label}`;
    }
    return `Badge: ${label}`;
  }
}

```
Page 2/7FirstPrevNextLast