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

# Directory Structure

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

# Files

--------------------------------------------------------------------------------
/docs/contracts.md:
--------------------------------------------------------------------------------

```markdown
  1 | # The component contracts system serves two primary purposes:
  2 |  - **Breaking change detection** during refactoring and validation
  3 | - **Documentation** of successful refactoring patterns for future reference
  4 | 
  5 | ## Table of Contents
  6 | 1. [File Organization & Storage Structure](#file-organization--storage-structure) — where contracts and diffs live
  7 | 2. [What a Contract Includes](#what-a-contract-includes) — data captured in a snapshot
  8 | 3. [When to Build a Contract](#when-to-build-a-contract) — baseline vs validation
  9 | 4. [When to Generate Diffs](#when-to-generate-diffs) — automated and manual diffing
 10 | 5. [Integration with Refactoring Rules Workflow](#integration-with-refactoring-rules-workflow) — contracts in 5-step automation
 11 | 6. [Post-Review & Hot-Fix Workflow](#post-review--hot-fix-workflow) — fixing bugs after validation
 12 | 7. [Building a Refactoring Knowledge Base](#building-a-refactoring-knowledge-base) — storing proven patterns
 13 | 
 14 | ## File Organization & Storage Structure
 15 | 
 16 | Contracts are organised in a predictable, component-scoped directory tree:
 17 | 
 18 | ```
 19 | .cursor/tmp/contracts/
 20 | ├── badge/                           # Component-specific directory
 21 | │   ├── ui-header-20250703T185531Z.contract.json
 22 | │   ├── ui-header-20250703T192519Z.contract.json
 23 | │   └── diffs/                          # Diff files subdirectory
 24 | │       └── diff-header-20250703T194046Z.json
 25 | ├── button/
 26 | │   ├── feature-modal-20250704T120000Z.contract.json
 27 | │   └── diffs/
 28 | └── input/
 29 |     ├── login-form-20250705T090000Z.contract.json
 30 |     └── diffs/
 31 | ```
 32 | 
 33 | **Key Highlights:**
 34 | - **Component-scoped directories**
 35 | - **Timestamped contract files**
 36 | - **Component-specific diff folders**
 37 | - **Predictable naming** (`diff-<component>-<timestamp>.json`)
 38 | 
 39 | ## What a Contract Includes
 40 | 
 41 | Each contract captures a comprehensive snapshot of a component:
 42 | 
 43 | ### Public API
 44 | - **Properties**: Input/output properties with types and default values
 45 | - **Events**: EventEmitter declarations and their types
 46 | - **Methods**: Public methods with parameters and return types
 47 | - **Lifecycle hooks**: Implemented Angular lifecycle interfaces
 48 | - **Imports**: All imported dependencies and their sources
 49 | 
 50 | ### DOM Structure
 51 | - **Element hierarchy**: Complete DOM tree with parent-child relationships
 52 | - **Attributes**: Static and dynamic attributes on elements
 53 | - **Bindings**: Property bindings, event handlers, and structural directives
 54 | - **Content projection**: ng-content slots and their selectors
 55 | 
 56 | ### Styles
 57 | - **CSS rules**: All styles applied to DOM elements
 58 | - **Element mapping**: Which styles apply to which DOM elements
 59 | - **Source tracking**: Whether styles come from component files or external stylesheets
 60 | 
 61 | Because contracts track every public-facing facet of a component, any refactor that breaks its API or behaviour is flagged immediately.
 62 | 
 63 | ## How do I build a contract?
 64 | 
 65 | Rules taking care about the contract building during the workflow, but if you need to build it "manually" say in the chat:
 66 | 
 67 | ```
 68 | build_component_contract(saveLocation, typescriptFile, templateFile?, styleFile?, dsComponentName?)
 69 | ``` 
 70 | 
 71 | > Replace the parameters with:
 72 | > - `saveLocation`: Path where to save the contract file (supports absolute and relative paths)
 73 | > - `typescriptFile`: Path to the TypeScript component file (.ts) — **Required**
 74 | > - `templateFile`: *(Optional)* Path to the component template file (.html). Omit for inline templates
 75 | > - `styleFile`: *(Optional)* Path to the component style file (.scss, .css, etc.). Omit for inline styles or components without styles
 76 | > - `dsComponentName`: *(Optional)* Design system component name (e.g., `DsBadge`)
 77 | > 
 78 | > The tool analyses the template, TypeScript, and styles, then saves the contract to your specified location.
 79 | > 
 80 | > **Note**: Angular components can have inline templates and styles. If `templateFile` or `styleFile` are not provided, the tool will extract inline template/styles from the TypeScript file.
 81 | 
 82 | ## When to Build a Contract
 83 | 
 84 | ### Core Principle
 85 | 
 86 | **Build a new contract whenever a component changes.** This ensures you have an accurate snapshot of the component's state at each critical point in its evolution.
 87 | 
 88 | ### Pre-Refactoring Contract (Baseline)
 89 | 
 90 | Always build an initial contract **before** starting any refactoring work. This creates your baseline for comparison.
 91 | 
 92 | - **Automated workflow**: Handled automatically by the refactoring rules (see `03-fix-violations.mdc`)
 93 | - **Manual workflow**: Build the contract manually before making any changes
 94 | 
 95 | ### Post-Refactoring Contract (Validation)
 96 | 
 97 | Build a new contract **after** completing your refactoring work to capture the final state.
 98 | 
 99 | - **Automated workflow**: Generated during the validation phase (see `04-validate-changes.mdc`)
100 | - **Manual workflow**: Build the contract after completing all changes
101 | 
102 | ### Multiple Contract States
103 | 
104 | For workflows involving QA, E2E testing, or UAT phases, build additional contracts if the component changes during or after testing. 
105 | 
106 | **Best practice**: Create a new contract for each significant milestone where the component is modified.
107 | 
108 | ## When to Generate Diffs
109 | 
110 | ### Automated Workflow Diffs
111 | 
112 | Contract diffs are automatically generated during the validation phase (see `04-validate-changes.mdc`). These diffs enable AI-powered validation of refactoring changes.
113 | 
114 | ### Manual Workflow Diffs
115 | 
116 | When refactoring manually or outside the automated rules workflow, generate diffs to:
117 | - Identify breaking or risky changes
118 | - Get AI analysis of the refactoring impact
119 | - Validate that changes meet expectations
120 | 
121 | ## Integration with Refactoring Rules Workflow
122 | 
123 | The contracts system is fully integrated into the 5-step refactoring workflow:
124 | 
125 | ### Step 1: Find Violations (`01-find-violations.mdc`)
126 | - **Purpose**: Identify legacy component usage across the codebase
127 | - **Contract role**: No contracts generated at this stage
128 | - **Output**: Ranked list of folders and files with violations
129 | 
130 | ### Step 2: Plan Refactoring (`02-plan-refactoring.mdc`)
131 | - **Purpose**: Create detailed migration plan for each affected component
132 | - **Contract role**: Analysis of component structure informs refactoring strategy
133 | - **Output**: Comprehensive migration plan with complexity scoring
134 | 
135 | **Note on Non-Viable Cases**: When components are identified as non-viable during step 2 and developer approval is obtained, the non-viable cases handling (`03-non-viable-cases.mdc`) is used instead of proceeding to steps 3-5. This handling does not use contracts as it maintains existing component structure while marking components for exclusion from future reports.
136 | 
137 | ### Step 3: Fix Violations (`03-fix-violations.mdc`)
138 | - **Purpose**: Execute the refactoring plan systematically
139 | - **Contract role**: **Pre-refactoring contracts are automatically generated** for each component before changes begin
140 | - **Key integration**: `build_component_contract(component_files, dsComponentName)` creates baseline contracts
141 | - **Output**: Refactored components with baseline contracts stored
142 | 
143 | ### Step 4: Validate Changes (`04-validate-changes.mdc`)
144 | - **Purpose**: Verify refactoring safety and detect breaking changes
145 | - **Contract role**: **Post-refactoring contracts are generated and compared** against baselines
146 | - **Key integration**: 
147 |   - `build_component_contract()` captures refactored state
148 |   - `diff_component_contract()` compares before/after contracts
149 |   - AI analyzes diffs for breaking changes and risks
150 | - **Output**: Validation report highlighting risky changes
151 | 
152 | ### Step 5: Prepare Report (`05-prepare-report.mdc`)
153 | - **Purpose**: Generate testing checklists and documentation
154 | - **Contract role**: Contract diffs inform testing requirements and risk assessment
155 | - **Output**: Role-specific testing checklists and commit documentation
156 | 
157 | ## Post-Review & Hot-Fix Workflow
158 | 
159 | What happens when QA finds a bug or a reviewer requests changes **after** the initial refactor has already been validated?
160 | 
161 | 1. **Apply the Code Fix** – attach the changed component file(s).
162 | 2. **Re-build the "latest" contract**
163 |    ```
164 |    User: build_component_contract(<changed-file.ts>, dsComponentName)
165 |    ```
166 |    The new snapshot will be stored alongside the previous ones in
167 |    `.cursor/tmp/contracts/<ds-component-kebab>/`.
168 | 3. **Locate the original baseline contract** – this is the contract that was captured for the initial state (usually the very first timestamp in the folder).
169 | 4. **Generate a diff** between the baseline and the latest contract:
170 |    ```
171 |    User: diff_component_contract(saveLocation, contractBeforePath, contractAfterPath, dsComponentName)
172 |    ```
173 |    > Replace the parameters with:
174 |    > - `saveLocation`: Path where to save the diff result file (supports absolute and relative paths)
175 |    > - `contractBeforePath`: Path to the baseline contract file
176 |    > - `contractAfterPath`: Path to the latest contract file
177 |    > - `dsComponentName`: Optional design system component name
178 | 5. **Review the diff output using AI** – attach the diff and ask it to analyze it.
179 |    * If only intentional changes appear, proceed to merge / re-test.
180 |    * If unexpected API, DOM, or style changes surface, iterate on the fix and repeat steps 1-4.
181 | 
182 | ### Why keep the original baseline?
183 | 
184 | Diffing against the **first** snapshot ensures you do not
185 | inadvertently mask breaking changes introduced during multiple fix cycles.
186 | 
187 | ### Tip: Cleaning up old snapshots
188 | 
189 | Once a hot-fix is approved, you may delete intermediate contract and diff files to
190 | reduce noise and keep the folder tidy – leave the original baseline, final state and the
191 | latest approved diff. You can manually move it to `.cursor/tmp/patterns/ds-component-name`.
192 | 
193 | ## Building a Refactoring Knowledge Base
194 | 
195 | Consider storing successful diffs (that passed all checks and testing) to build a knowledge base of proven refactoring patterns. This is particularly valuable when:
196 | 
197 | - Refactoring hundreds or thousands of similar components
198 | - Establishing team standards for common refactoring scenarios
199 | - Training new team members on safe refactoring practices
200 | - Automating similar refactoring tasks in the future
201 | 
```

--------------------------------------------------------------------------------
/docs/tools.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Design System Tools for AI Agents
  2 | 
  3 | This document provides comprehensive guidance for AI agents working with Angular Design System (DS) migration and analysis tools. Each tool is designed to support automated refactoring, validation, and analysis workflows.
  4 | 
  5 | ## Tool Categories
  6 | 
  7 | ### 🔍 Project Analysis Tools
  8 | 
  9 | #### `report-violations`
 10 | **Purpose**: Identifies deprecated DS CSS usage patterns in Angular projects
 11 | **AI Usage**: Use as the first step in migration workflows to identify all violations before planning refactoring
 12 | **Key Parameters**:
 13 | - `directory`: Target analysis directory (use relative paths like `./src/app`)
 14 | - `componentName`: DS component class name (e.g., `DsButton`)
 15 | - `groupBy`: `"file"` or `"folder"` for result organization
 16 | **Output**: Structured violation reports grouped by file or folder
 17 | **Best Practice**: Always run this before other migration tools to establish baseline
 18 | 
 19 | #### `report-all-violations`
 20 | **Purpose**: Reports all deprecated DS CSS usage for every DS component within a directory
 21 | **AI Usage**: Use for a fast, global inventory of violations across the codebase before narrowing to specific components
 22 | **Key Parameters**:
 23 | - `directory`: Target analysis directory (use relative paths like `./src/app`)
 24 | - `groupBy`: `"file"` or `"folder"` for result organization (default: `"file"`)
 25 | **Output**: Structured violation reports grouped by file or folder covering all DS components
 26 | **Best Practice**: Use to discover all violations and establish the baseline for subsequent refactoring.
 27 | 
 28 | #### `get-project-dependencies`
 29 | **Purpose**: Analyzes project structure, dependencies, and buildability
 30 | **AI Usage**: Validate project architecture before suggesting refactoring strategies
 31 | **Key Parameters**:
 32 | - `directory`: Project directory to analyze
 33 | - `componentName`: Optional DS component for import path validation
 34 | **Output**: Dependency analysis, buildable/publishable status, peer dependencies
 35 | **Best Practice**: Use to understand project constraints before recommending changes
 36 | 
 37 | #### `report-deprecated-css`
 38 | **Purpose**: Scans styling files for deprecated CSS classes
 39 | **AI Usage**: Complement violation reports with style-specific analysis
 40 | **Key Parameters**:
 41 | - `directory`: Directory containing style files
 42 | - `componentName`: Target DS component
 43 | **Output**: List of deprecated CSS classes found in stylesheets
 44 | **Best Practice**: Run after `report-violations` for comprehensive CSS analysis
 45 | 
 46 | ### 📚 Component Information Tools
 47 | 
 48 | #### `list-ds-components`
 49 | **Purpose**: Lists all available Design System components in the project with their file paths and metadata
 50 | **AI Usage**: Discover available DS components before starting migration or analysis workflows
 51 | **Key Parameters**:
 52 | - `sections`: Array of sections to include - `"implementation"`, `"documentation"`, `"stories"`, or `"all"` (default: `["all"]`)
 53 | **Output**: Complete inventory of DS components with their implementation files, documentation files, stories files, and import paths
 54 | **Best Practice**: Use as the first step to understand the DS component landscape before targeted analysis
 55 | 
 56 | #### `get-ds-component-data`
 57 | **Purpose**: Returns comprehensive data for a specific DS component including implementation files, documentation files, stories files, and import path
 58 | **AI Usage**: Get detailed information about a specific component for analysis or migration planning
 59 | **Key Parameters**:
 60 | - `componentName`: DS component class name (e.g., `DsBadge`)
 61 | - `sections`: Array of sections to include - `"implementation"`, `"documentation"`, `"stories"`, or `"all"` (default: `["all"]`)
 62 | **Output**: Structured data with file paths for implementation, documentation, stories, and import information
 63 | **Best Practice**: Use selective sections to optimize performance when you only need specific types of files
 64 | 
 65 | #### `get-component-docs`
 66 | **Purpose**: Retrieves MDX documentation for DS components
 67 | **AI Usage**: Access official component documentation to understand proper usage patterns
 68 | **Key Parameters**:
 69 | - `componentName`: DS component class name (e.g., `DsButton`)
 70 | **Output**: API documentation and usage examples in MDX format
 71 | **Best Practice**: Always consult docs before suggesting component usage changes
 72 | 
 73 | #### `get-component-paths`
 74 | **Purpose**: Provides filesystem and NPM import paths for DS components
 75 | **AI Usage**: Verify correct import paths when suggesting code changes
 76 | **Key Parameters**:
 77 | - `componentName`: DS component class name
 78 | **Output**: Source directory path and NPM import path
 79 | **Best Practice**: Use to ensure accurate import statements in generated code
 80 | 
 81 | #### `get-deprecated-css-classes`
 82 | **Purpose**: Lists deprecated CSS classes for specific DS components
 83 | **AI Usage**: Understand what CSS classes to avoid or replace during migration
 84 | **Key Parameters**:
 85 | - `componentName`: DS component class name
 86 | **Output**: Array of deprecated CSS class names
 87 | **Best Practice**: Cross-reference with violation reports to prioritize fixes
 88 | 
 89 | ### 🔗 Analysis & Mapping Tools
 90 | 
 91 | #### `build-component-usage-graph`
 92 | **Purpose**: Maps component usage across modules, specs, templates, and styles
 93 | **AI Usage**: Understand component dependencies before refactoring to avoid breaking changes
 94 | **Key Parameters**:
 95 | - `directory`: Root directory for analysis
 96 | - `violationFiles`: Array of files with violations (from `report-violations`)
 97 | **Output**: Component usage graph showing all import relationships
 98 | **Best Practice**: Essential for large refactoring projects to map impact scope
 99 | 
100 | #### `lint-changes`
101 | **Purpose**: Runs ESLint validation on changed Angular files
102 | **AI Usage**: Validate code quality after making automated changes
103 | **Key Parameters**:
104 | - `directory`: Root directory containing components
105 | - `files`: Optional list of changed files
106 | - `configPath`: Optional ESLint config path
107 | **Output**: ESLint results and violations
108 | **Best Practice**: Always run after code modifications to ensure quality
109 | 
110 | ### 📋 Component Contract Tools
111 | 
112 | #### `build_component_contract`
113 | **Purpose**: Creates static surface contracts for component templates and styles
114 | **AI Usage**: Generate contracts before refactoring to track breaking changes
115 | **Key Parameters**:
116 | - `saveLocation`: Path where to save the contract file (supports absolute and relative paths)
117 | - `typescriptFile`: **Required** TypeScript component file (.ts)
118 | - `templateFile`: *Optional* Template file name (.html). Omit for inline templates
119 | - `styleFile`: *Optional* Style file name (.scss, .css, etc.). Omit for inline styles or no styles
120 | - `dsComponentName`: *Optional* design system component name
121 | **Output**: Component contract file with API surface
122 | **Best Practice**: Create contracts before major refactoring for comparison. Template and style files are optional—the tool will extract inline templates/styles from the TypeScript file when not provided
123 | 
124 | #### `diff_component_contract`
125 | **Purpose**: Compares before/after contracts to identify breaking changes
126 | **AI Usage**: Validate that refactoring doesn't introduce breaking changes
127 | **Key Parameters**:
128 | - `saveLocation`: Path where to save the diff result file (supports absolute and relative paths)
129 | - `contractBeforePath`: Path to pre-refactoring contract
130 | - `contractAfterPath`: Path to post-refactoring contract
131 | - `dsComponentName`: Optional design system component name
132 | **Output**: Diff analysis showing breaking changes
133 | **Best Practice**: Essential validation step after component modifications
134 | 
135 | #### `list_component_contracts`
136 | **Purpose**: Lists all available component contracts
137 | **AI Usage**: Discover existing contracts for comparison operations
138 | **Key Parameters**:
139 | - `directory`: Directory to search for contracts
140 | **Output**: List of available contract files
141 | **Best Practice**: Use to manage contract lifecycle during refactoring
142 | 
143 | ### ⚙️ Configuration Tools
144 | 
145 | ## AI Agent Workflow Patterns
146 | 
147 | ### 1. Discovery & Analysis Workflow
148 | ```
149 | 1. list-ds-components → Discover available DS components
150 | 2. report-violations → Identify all violations
151 | 3. get-project-dependencies → Analyze project structure
152 | ```
153 | 
154 | ### 2. Planning & Preparation Workflow
155 | ```
156 | 1. get-ds-component-data → Get comprehensive component information
157 | 2. build-component-usage-graph → Map component relationships
158 | 3. get-component-docs → Review proper usage patterns
159 | 4. get-component-paths → Verify import paths
160 | 5. build_component_contract → Create baseline contracts
161 | ```
162 | 
163 | ### 3. Refactoring & Validation Workflow
164 | ```
165 | 1. [Apply code changes]
166 | 2. build_component_contract → Create post-change contracts
167 | 3. diff_component_contract → Validate no breaking changes
168 | 4. lint-changes → Ensure code quality
169 | ```
170 | 
171 | ### 4. Non-Viable Cases Handling (Alternative to Steps 3-5)
172 | ```
173 | 1. report-deprecated-css → Identify CSS usage in global styles
174 | 2. report-deprecated-css → Identify CSS usage in component overrides
175 | 3. [Replace HTML classes with after-migration- prefix]
176 | 4. [Duplicate CSS selectors with prefixed versions]
177 | 5. report-deprecated-css → Validate CSS count consistency
178 | 6. report-violations → Validate violation reduction
179 | ```
180 | **Purpose**: Used during the main DS refactoring workflow when components are identified as non-viable during planning step
181 | **Trigger**: Requires developer review and approval after AI identifies non-viable cases in step 2
182 | **Key Pattern**: Use `after-migration-[ORIGINAL_CLASS]` prefix to exclude components from future analysis
183 | **Replaces**: Normal fix violations → validate changes → prepare report sequence
184 | 
185 | ## Error Handling for AI Agents
186 | 
187 | - **Path Resolution**: Always use relative paths starting with `./`
188 | - **Component Names**: Use PascalCase with `Ds` prefix (e.g., `DsButton`)
189 | - **File Arrays**: Ensure violation file arrays are properly formatted
190 | - **Directory Validation**: Verify directories exist before analysis
191 | - **Contract Management**: Clean up temporary contracts after analysis
192 | 
193 | ## Performance Considerations
194 | 
195 | - Use `groupBy: "folder"` for large codebases to reduce output size
196 | - Limit `violationFiles` arrays to relevant files only
197 | - Use selective `sections` parameter in `get-ds-component-data` and `list-ds-components` to retrieve only needed data types
198 | - Cache component documentation between related operations
199 | - Run validation tools in parallel when possible
200 | 
201 | ## Integration Points
202 | 
203 | These tools integrate with:
204 | - **Storybook**: For component documentation
205 | - **PostCSS**: For style analysis
206 | 
207 | ## Output Formats
208 | 
209 | All tools return structured data suitable for:
210 | - JSON parsing for programmatic analysis
211 | - Markdown formatting for human-readable reports
212 | - File path arrays for batch operations
213 | - Contract objects for API comparison 
```

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

```markdown
  1 | # Examples
  2 | 
  3 | ## 1 — Identifying Angular Component decorators
  4 | 
  5 | > Find and validate `@Component` decorators in Angular class declarations.
  6 | 
  7 | ```ts
  8 | import {
  9 |   isComponentDecorator,
 10 |   getDecorators,
 11 | } from '@push-based/typescript-ast-utils';
 12 | import * as ts from 'typescript';
 13 | 
 14 | // Sample Angular component source code
 15 | const sourceCode = `
 16 | @Component({
 17 |   selector: 'app-example',
 18 |   template: '<div>Hello World</div>'
 19 | })
 20 | export class ExampleComponent {}
 21 | `;
 22 | 
 23 | // Create source file and program
 24 | const sourceFile = ts.createSourceFile(
 25 |   'example.ts',
 26 |   sourceCode,
 27 |   ts.ScriptTarget.Latest
 28 | );
 29 | 
 30 | // Visit class declarations
 31 | function visitClassDeclaration(node: ts.ClassDeclaration) {
 32 |   const decorators = getDecorators(node);
 33 | 
 34 |   for (const decorator of decorators) {
 35 |     if (isComponentDecorator(decorator)) {
 36 |       console.log(`Found @Component decorator on class: ${node.name?.text}`);
 37 |       // → 'Found @Component decorator on class: ExampleComponent'
 38 |     }
 39 |   }
 40 | }
 41 | 
 42 | // Traverse the AST
 43 | ts.forEachChild(sourceFile, function visit(node) {
 44 |   if (ts.isClassDeclaration(node)) {
 45 |     visitClassDeclaration(node);
 46 |   }
 47 |   ts.forEachChild(node, visit);
 48 | });
 49 | ```
 50 | 
 51 | ---
 52 | 
 53 | ## 2 — Generic decorator detection
 54 | 
 55 | > Detect any decorator by name or check for any decorators on a node.
 56 | 
 57 | ```ts
 58 | import { isDecorator, getDecorators } from '@push-based/typescript-ast-utils';
 59 | import * as ts from 'typescript';
 60 | 
 61 | const sourceCode = `
 62 | @Injectable()
 63 | @Component({
 64 |   selector: 'app-service'
 65 | })
 66 | @CustomDecorator('config')
 67 | export class ServiceComponent {}
 68 | `;
 69 | 
 70 | const sourceFile = ts.createSourceFile(
 71 |   'service.ts',
 72 |   sourceCode,
 73 |   ts.ScriptTarget.Latest
 74 | );
 75 | 
 76 | function analyzeDecorators(node: ts.ClassDeclaration) {
 77 |   const decorators = getDecorators(node);
 78 | 
 79 |   console.log(`Found ${decorators.length} decorators`); // → 'Found 3 decorators'
 80 | 
 81 |   for (const decorator of decorators) {
 82 |     // Check for specific decorators
 83 |     if (isDecorator(decorator, 'Injectable')) {
 84 |       console.log('Has @Injectable decorator');
 85 |     }
 86 | 
 87 |     if (isDecorator(decorator, 'Component')) {
 88 |       console.log('Has @Component decorator');
 89 |     }
 90 | 
 91 |     if (isDecorator(decorator, 'CustomDecorator')) {
 92 |       console.log('Has @CustomDecorator decorator');
 93 |     }
 94 | 
 95 |     // Check if it's any valid decorator
 96 |     if (isDecorator(decorator)) {
 97 |       console.log('Found a valid decorator');
 98 |     }
 99 |   }
100 | }
101 | 
102 | // Output:
103 | // → 'Found 3 decorators'
104 | // → 'Has @Injectable decorator'
105 | // → 'Found a valid decorator'
106 | // → 'Has @Component decorator'
107 | // → 'Found a valid decorator'
108 | // → 'Has @CustomDecorator decorator'
109 | // → 'Found a valid decorator'
110 | ```
111 | 
112 | ---
113 | 
114 | ## 3 — Removing quotes from string literals
115 | 
116 | > Clean quoted strings from AST nodes for processing.
117 | 
118 | ```ts
119 | import { removeQuotes } from '@push-based/typescript-ast-utils';
120 | import * as ts from 'typescript';
121 | 
122 | const sourceCode = `
123 | const singleQuoted = 'hello world';
124 | const doubleQuoted = "typescript utils";
125 | const backtickQuoted = \`template string\`;
126 | const multipleQuotes = """heavily quoted""";
127 | `;
128 | 
129 | const sourceFile = ts.createSourceFile(
130 |   'strings.ts',
131 |   sourceCode,
132 |   ts.ScriptTarget.Latest
133 | );
134 | 
135 | function processStringLiterals(node: ts.Node) {
136 |   if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
137 |     const originalText = node.getText(sourceFile);
138 |     const cleanedText = removeQuotes(node, sourceFile);
139 | 
140 |     console.log(`Original: ${originalText} → Cleaned: "${cleanedText}"`);
141 |   }
142 | }
143 | 
144 | ts.forEachChild(sourceFile, function visit(node) {
145 |   processStringLiterals(node);
146 |   ts.forEachChild(node, visit);
147 | });
148 | 
149 | // Output:
150 | // → Original: 'hello world' → Cleaned: "hello world"
151 | // → Original: "typescript utils" → Cleaned: "typescript utils"
152 | // → Original: `template string` → Cleaned: "template string"
153 | // → Original: """heavily quoted""" → Cleaned: "heavily quoted"
154 | ```
155 | 
156 | ---
157 | 
158 | ## 4 — Safe decorator extraction across TypeScript versions
159 | 
160 | > Handle different TypeScript compiler API versions when extracting decorators.
161 | 
162 | ```ts
163 | import { getDecorators, hasDecorators } from '@push-based/typescript-ast-utils';
164 | import * as ts from 'typescript';
165 | 
166 | const sourceCode = `
167 | @Deprecated()
168 | @Component({
169 |   selector: 'legacy-component'
170 | })
171 | export class LegacyComponent {
172 |   @Input() data: string;
173 |   
174 |   @Output() change = new EventEmitter();
175 | }
176 | `;
177 | 
178 | const sourceFile = ts.createSourceFile(
179 |   'legacy.ts',
180 |   sourceCode,
181 |   ts.ScriptTarget.Latest
182 | );
183 | 
184 | function safelyExtractDecorators(node: ts.Node) {
185 |   // Safe extraction that works across TypeScript versions
186 |   const decorators = getDecorators(node);
187 | 
188 |   if (decorators.length > 0) {
189 |     console.log(`Node has ${decorators.length} decorators`);
190 | 
191 |     // Type-safe check
192 |     if (hasDecorators(node)) {
193 |       console.log('Confirmed: node has decorators property');
194 |     }
195 |   }
196 | 
197 |   return decorators;
198 | }
199 | 
200 | // Process class and its members
201 | ts.forEachChild(sourceFile, function visit(node) {
202 |   if (ts.isClassDeclaration(node)) {
203 |     console.log(`Class decorators: ${safelyExtractDecorators(node).length}`);
204 |     // → 'Class decorators: 2'
205 | 
206 |     // Check property decorators
207 |     for (const member of node.members) {
208 |       if (ts.isPropertyDeclaration(member)) {
209 |         const memberDecorators = safelyExtractDecorators(member);
210 |         if (memberDecorators.length > 0) {
211 |           console.log(
212 |             `Property "${member.name?.getText(sourceFile)}" has ${
213 |               memberDecorators.length
214 |             } decorators`
215 |           );
216 |           // → 'Property "data" has 1 decorators'
217 |           // → 'Property "change" has 1 decorators'
218 |         }
219 |       }
220 |     }
221 |   }
222 | 
223 |   ts.forEachChild(node, visit);
224 | });
225 | ```
226 | 
227 | ---
228 | 
229 | ## 5 — Building a decorator analyzer tool
230 | 
231 | > Create a comprehensive tool to analyze all decorators in a TypeScript file.
232 | 
233 | ```ts
234 | import {
235 |   getDecorators,
236 |   isDecorator,
237 |   isComponentDecorator,
238 |   removeQuotes,
239 | } from '@push-based/typescript-ast-utils';
240 | import * as ts from 'typescript';
241 | 
242 | interface DecoratorInfo {
243 |   name: string;
244 |   target: string;
245 |   arguments: string[];
246 |   line: number;
247 | }
248 | 
249 | class DecoratorAnalyzer {
250 |   private decorators: DecoratorInfo[] = [];
251 | 
252 |   analyze(
253 |     sourceCode: string,
254 |     fileName: string = 'analysis.ts'
255 |   ): DecoratorInfo[] {
256 |     const sourceFile = ts.createSourceFile(
257 |       fileName,
258 |       sourceCode,
259 |       ts.ScriptTarget.Latest
260 |     );
261 |     this.decorators = [];
262 | 
263 |     this.visitNode(sourceFile, sourceFile);
264 |     return this.decorators;
265 |   }
266 | 
267 |   private visitNode(node: ts.Node, sourceFile: ts.SourceFile) {
268 |     const decorators = getDecorators(node);
269 | 
270 |     if (decorators.length > 0) {
271 |       const targetName = this.getTargetName(node, sourceFile);
272 | 
273 |       for (const decorator of decorators) {
274 |         const decoratorInfo = this.extractDecoratorInfo(
275 |           decorator,
276 |           targetName,
277 |           sourceFile
278 |         );
279 |         if (decoratorInfo) {
280 |           this.decorators.push(decoratorInfo);
281 |         }
282 |       }
283 |     }
284 | 
285 |     ts.forEachChild(node, (child) => this.visitNode(child, sourceFile));
286 |   }
287 | 
288 |   private extractDecoratorInfo(
289 |     decorator: ts.Decorator,
290 |     targetName: string,
291 |     sourceFile: ts.SourceFile
292 |   ): DecoratorInfo | null {
293 |     if (!isDecorator(decorator)) return null;
294 | 
295 |     const expression = decorator.expression;
296 |     let name = '';
297 |     const args: string[] = [];
298 | 
299 |     if (ts.isIdentifier(expression)) {
300 |       name = expression.text;
301 |     } else if (
302 |       ts.isCallExpression(expression) &&
303 |       ts.isIdentifier(expression.expression)
304 |     ) {
305 |       name = expression.expression.text;
306 | 
307 |       // Extract arguments
308 |       for (const arg of expression.arguments) {
309 |         if (ts.isStringLiteral(arg)) {
310 |           args.push(removeQuotes(arg, sourceFile));
311 |         } else {
312 |           args.push(arg.getText(sourceFile));
313 |         }
314 |       }
315 |     }
316 | 
317 |     const line =
318 |       sourceFile.getLineAndCharacterOfPosition(decorator.getStart()).line + 1;
319 | 
320 |     return {
321 |       name,
322 |       target: targetName,
323 |       arguments: args,
324 |       line,
325 |     };
326 |   }
327 | 
328 |   private getTargetName(node: ts.Node, sourceFile: ts.SourceFile): string {
329 |     if (ts.isClassDeclaration(node) && node.name) {
330 |       return `class ${node.name.text}`;
331 |     }
332 |     if (ts.isPropertyDeclaration(node) && node.name) {
333 |       return `property ${node.name.getText(sourceFile)}`;
334 |     }
335 |     if (ts.isMethodDeclaration(node) && node.name) {
336 |       return `method ${node.name.getText(sourceFile)}`;
337 |     }
338 |     return 'unknown';
339 |   }
340 | }
341 | 
342 | // Usage example
343 | const analyzer = new DecoratorAnalyzer();
344 | const sourceCode = `
345 | @Component({
346 |   selector: 'app-example',
347 |   template: '<div>Example</div>'
348 | })
349 | export class ExampleComponent {
350 |   @Input('inputAlias') data: string;
351 |   
352 |   @Output() change = new EventEmitter();
353 |   
354 |   @HostListener('click', ['$event'])
355 |   onClick(event: Event) {}
356 | }
357 | `;
358 | 
359 | const results = analyzer.analyze(sourceCode);
360 | results.forEach((info) => {
361 |   console.log(`Line ${info.line}: @${info.name} on ${info.target}`);
362 |   if (info.arguments.length > 0) {
363 |     console.log(`  Arguments: ${info.arguments.join(', ')}`);
364 |   }
365 | });
366 | 
367 | // Output:
368 | // → Line 1: @Component on class ExampleComponent
369 | // →   Arguments: { selector: 'app-example', template: '<div>Example</div>' }
370 | // → Line 6: @Input on property data
371 | // →   Arguments: inputAlias
372 | // → Line 8: @Output on property change
373 | // → Line 10: @HostListener on method onClick
374 | // →   Arguments: click, ['$event']
375 | ```
376 | 
377 | ---
378 | 
379 | ## 6 — Error handling and edge cases
380 | 
381 | > Handle malformed decorators and edge cases gracefully.
382 | 
383 | ```ts
384 | import { getDecorators, isDecorator } from '@push-based/typescript-ast-utils';
385 | import * as ts from 'typescript';
386 | 
387 | const problematicCode = `
388 | // Valid decorator
389 | @Component()
390 | export class ValidComponent {}
391 | 
392 | // Malformed decorator (will be handled gracefully)
393 | @
394 | export class MalformedDecorator {}
395 | 
396 | // Complex decorator expression
397 | @NgModule({
398 |   imports: [CommonModule],
399 |   declarations: [SomeComponent]
400 | })
401 | export class ComplexModule {}
402 | `;
403 | 
404 | function safeDecoratorAnalysis(sourceCode: string) {
405 |   try {
406 |     const sourceFile = ts.createSourceFile(
407 |       'test.ts',
408 |       sourceCode,
409 |       ts.ScriptTarget.Latest
410 |     );
411 | 
412 |     ts.forEachChild(sourceFile, function visit(node) {
413 |       if (ts.isClassDeclaration(node)) {
414 |         const decorators = getDecorators(node);
415 | 
416 |         console.log(`Analyzing class: ${node.name?.text || 'anonymous'}`);
417 |         console.log(`Found ${decorators.length} decorators`);
418 | 
419 |         for (const decorator of decorators) {
420 |           try {
421 |             if (isDecorator(decorator)) {
422 |               console.log('✓ Valid decorator found');
423 |             } else {
424 |               console.log('✗ Invalid decorator structure');
425 |             }
426 |           } catch (error) {
427 |             console.log(`⚠ Error processing decorator: ${error}`);
428 |           }
429 |         }
430 | 
431 |         console.log('---');
432 |       }
433 | 
434 |       ts.forEachChild(node, visit);
435 |     });
436 |   } catch (error) {
437 |     console.error('Failed to parse source code:', error);
438 |   }
439 | }
440 | 
441 | safeDecoratorAnalysis(problematicCode);
442 | 
443 | // Output:
444 | // → Analyzing class: ValidComponent
445 | // → Found 1 decorators
446 | // → ✓ Valid decorator found
447 | // → ---
448 | // → Analyzing class: MalformedDecorator
449 | // → Found 0 decorators
450 | // → ---
451 | // → Analyzing class: ComplexModule
452 | // → Found 1 decorators
453 | // → ✓ Valid decorator found
454 | // → ---
455 | ```
456 | 
457 | These examples demonstrate the comprehensive capabilities and practical usage patterns of the `@push-based/typescript-ast-utils` library for TypeScript AST analysis, decorator processing, and source code manipulation.
458 | 
```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/docs/angular-component-tree.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Angular Component Tree
  2 | 
  3 | This document describes the structure of an Angular component tree created by using the utils helper under `angular.`
  4 | The tree is a representation of the Angular component structure in a project. It is used to visualize the component hierarchy and the relationships between components.
  5 | 
  6 | ## File Content
  7 | 
  8 | - JS Content: `*{}` - shorthand for CSS text content
  9 | - HTML Content: `</>` - shorthand for HTML text content
 10 | - CSS Content: `{;}` - shorthand for JS text content
 11 | - JSON Content: `[:]` - shorthand for JSON text content
 12 | 
 13 | ## File-tree
 14 | 
 15 | - Sold Style: `━` - bold
 16 | - Tree: `┃` - Tree connection
 17 | - Branch: `┣━━` / `┗━━` - Content connection e.g. `Object property`
 18 | - Folder Connector: `📂` - the property name `children`
 19 | - File Name: `:` - any value `string`, `number`
 20 | - Important File: `:` - entry points e.g. `📦` repo; `🅰️`, `⚛️` framework; `🟦` stack, `📜` organisation
 21 | 
 22 | ### Example
 23 | 
 24 | ```bash
 25 | root
 26 | ┣━━ 📂src
 27 | ┃   ┗━━ 📂button
 28 | ┃       ┣━━ button.component.ts
 29 | ┃       ┣━━ 📂other-compoennt
 30 | ┃       ┗━━ 📂other-folder
 31 | ┃           ┗━━ button.component.ts
 32 | ┣━━ 📦package.json
 33 | ┣━━ 🟦tsconfig.json
 34 | ┣━━ 🅰️angular.json
 35 | ┗━━ 📜README.md
 36 | ```
 37 | 
 38 | ## Code-tree
 39 | 
 40 | - Line Type: `│` - Tree connection
 41 | - Tree Style: `─` - light
 42 | - Branch: `├` / `└` - Content connection e.g. `Object property`
 43 | - Branch Connector: `╼` - the property name `children`
 44 | - Array: `[ ]` - Information list e.g. `Array`, `Set`, `Iterable`
 45 | - Array Index: `[0]` - list item e.g. `Object property`
 46 | - Object: `{ }` - Information pairs e.g. `Class`, `Object`, `Map`
 47 | - Prop Name: `prop` - any value `string`
 48 | - Value Connector: `:` - separates property or index from value
 49 | - Prop Value: `42`, `"test"` - any value any value `string`, `number`
 50 | 
 51 | ### Example
 52 | 
 53 | ```bash
 54 | { } # component object
 55 |  ├╼ className: 'ButtonComponent' - # property: string
 56 |  └╼ styleUrls: [ ] # array
 57 |                 ├╼ [0]: { } # index 0 - first style object
 58 |                 │        ├╼ startLine: 4
 59 |                 │        └╼ value: './styles-1.css'
 60 |                 │                  └╼ value: './styles-1.css'
 61 |                 └╼ [1]: { }  # index 1 - second style object
 62 |                          ├╼ startLine: 2 - # property: number
 63 |                          └╼ value: './styles-2.css' - # property: string
 64 | ```
 65 | 
 66 | ## AST-tree
 67 | 
 68 | - Line Type: `│` - Tree connection
 69 | - Tree Style: `─` - light
 70 | - Branch: `├` / `└` - Content connection e.g. `Object property`
 71 | - Branch Connector: `↘` - the property name `children`
 72 | - Array: `[ ]` - Information list e.g. `Array`, `Set`, `Iterable`
 73 | - Array Index: `[0]` - list item e.g. `Object property`
 74 | - Object: `{ }` - Information pairs e.g. `Class`, `Object`, `Map`
 75 | - Prop Name: `prop` - any value `string`
 76 | - Value Connector: `:` - separates property or index from value
 77 | - Prop Value: `42`, `"test"` - any value any value `string`, `number`
 78 | 
 79 | ### Example
 80 | 
 81 | _`component.ts` - Text representation of the file content_
 82 | 
 83 | ```bash
 84 | export class BaseComponent {
 85 | styles: String;
 86 | }
 87 | 
 88 | export class Component {
 89 | styles = ['styles.css'];
 90 | }
 91 | ```
 92 | 
 93 | _AbstractSyntaxTree representation of the file content of `component.ts`_
 94 | 
 95 | ```bash
 96 | ( ) # `sourceFile` - A plain JavaScript function returning a object
 97 |  └╼ sourceFile: TsAstNode # Start of AST tree
 98 |                 ├↘ [0]: ClassDeclaration # shorter form us array syntax is used
 99 |                 └↘ [1]: ClassDeclaration
100 |                         ├↘ ClassDeclaration
101 |                         ├↘ FunctionDeclaration
102 |                         └↘ PropertyDeclaration
103 |                            └↘ ObjectLiteralExpression
104 |                               └↘ PropertyAssignment
105 |                                  └↘ Identifier
106 |                                     └↘ getText(): './button.css' # Function returning `./button.css`
107 |                                        ⤷ `.btn { color: red; }` # './button.css' content
108 | ```
109 | 
110 | ## Tree Links
111 | 
112 | - File System Reference: `⤷` - links a file reference to it's content
113 | - In Memory Reference: `↳` - links a reference to values, pairs or lists
114 | - In Memory Reference: `↳` - links a reference to values, pairs or lists
115 | 
116 | ### File System Reference
117 | 
118 | ```bash
119 | root
120 | ┗━━ 📂constants
121 |     ┣━━ button.ts  # const buttonStylePath = './button.css'
122 |     ┃   ⤷ `.btn { color: red; }` # './button.css' content
123 |     ┗━━ select.ts # const selectTemplatePath = './select.css'
124 |         ⤷ `<button class="btn btn-primary">Click me</button>` # './select.css' content
125 | ```
126 | 
127 | ### In Memory Reference to File System
128 | 
129 | ```bash
130 | { } # The default export of 'file.ts' file. (a JavaScript object)
131 |  ├╼ className: 'ButtonComponent' - # property: string
132 |  └╼ styleUrls: [ ] # array
133 |                 └╼ [0] './button.css' # index 0
134 |                         ⤷ `.btn { color: red; }` # './button.css' content
135 | ```
136 | 
137 | ### In Memory Reference - AST to FileSystem
138 | 
139 | ```bash
140 | ( ) # `sourceFile` - A plain JavaScript function returning a object
141 |  └╼ sourceFile:
142 |     └╼ sourceFile: ObjectLiteralExpression
143 |                    └↘ PropertyAssignment
144 |                       └↘ Identifier
145 |                          └↘ getText(): './button.css' # Function returning `./button.css`
146 |                             ⤷ `.btn { color: red; }` # './button.css' content
147 | ```
148 | 
149 | ## Angular Projects
150 | 
151 | ### Minimal Angular Project - File Tree
152 | 
153 | ```bash
154 | root
155 | ┣━━ 📂public
156 | ┣━━ 📂src
157 | ┃   ┣━━ 📂app
158 | ┃   ┃   ┣━━ 📂until
159 | ┃   ┃   ┃   ┣━━ 📂button
160 | ┃   ┃   ┃   ┃   ┗━━ button.component.ts
161 | ┃   ┃   ┃   ┃        ↳ inline-css
162 | ┃   ┃   ┃   ┃        ↳ inline-html
163 | ┃   ┃   ┃   ┣━━ 📂select
164 | ┃   ┃   ┃   ┃   ┣━━ select.component.ts
165 | ┃   ┃   ┃   ┃   ┣━━ ⤷ select.component.css
166 | ┃   ┃   ┃   ┃   ┗━━ ⤷ select.component.html
167 | ┃   ┃   ┃   ┗━━...
168 | ┃   ┃   ┣━━ app.routes.ts
169 | ┃   ┃   ┣━━ app.component.ts
170 | ┃   ┃   ┗━━ app.config.ts
171 | ┃   ┣━━ index.html
172 | ┃   ┣━━ main.ts
173 | ┃   ┗━━ styles.css
174 | ┣━━ 📦package.json
175 | ┣━━ 🟦tsconfig.json
176 | ┣━━ 🅰️angular.json
177 | ┗━━ README.md
178 | ```
179 | 
180 | ### Inline Assets (Styles and Templates)
181 | 
182 | ```bash
183 | root
184 | ┗━━ 📂any
185 |     ┗━━ any.component.ts
186 |         ├╼ styles: [ ]
187 |         │           ├╼ [0]: `.btn { size: 13px; }`
188 |         │           └╼ [1]: `.red { color: red; }`
189 |         └╼ template: `<button class="btn red">Click me</button>`
190 | ```
191 | 
192 | ### External Assets (Styles and Templates)
193 | 
194 | ```bash
195 | root
196 | ┣━━ 📂any
197 |     ┣━━ any.component.ts
198 |     ┃   ├╼ styleUrls: [ ]
199 |     ┃   │              ├╼ [0]: `any.styles.css`
200 |     ┃   │              │        ⤷ `.btn { size: 13px; }`
201 |     ┃   │              └╼ [1]: `other.styles.css`
202 |     ┃   │                       ⤷ `.red { color: red; }`
203 |     ┃   └╼ templateUrl: 'any.component.html'
204 |     ┃                    ⤷ `<button class="btn red">Click me</button>`
205 |     ┣━━ any.style.css
206 |     ┃   └╼ `.btn { color: red; }`
207 |     ┣━━ other.style-1.css
208 |     ┃   └╼ `.btn-primary { color: blue; }`
209 |     ┗━━ any.component.html
210 |         └╼ `<button class="btn btn-primary">Click me</button>`
211 | ```
212 | 
213 | ## Creating Component AST's
214 | 
215 | ### 1. Find Component Files - Regex matching
216 | 
217 | This part of the process should get optimized for scale as it is one of the costly steps.
218 | We use simple regex matching against a string pattern to detect interesting files.
219 | It is accepted that some of the matching files don't contain components (false positives), as they are later on excluded anyway.
220 | 
221 | ```bash
222 | [ ]
223 |  ├╼ [0]: 'src/app/app.component.ts'
224 |  ├╼ [1]: 'src/app/until/button/button.component.ts'
225 |  └╼ [2]: 'src/app/until/select.component.ts'
226 | ```
227 | 
228 | ### 2. Create the TS Program - Read Files and Parse AST
229 | 
230 | In this step we need to feed the TS program our entry to the frameworks TS code.
231 | 
232 | The entry is located in Angular's RC file `angular.json`.
233 | 
234 | ```bash
235 | root
236 | ┗━━ angular.json
237 |     ⤷ index.html
238 |     ⤷ styles.css
239 |     ⤷ tsconfig.json
240 |     ⤷ └↳main.ts # TSProgram entry
241 |         └↘ app.config.ts
242 |            └↘ app.routes.ts
243 |               └↘ app/app.component.ts
244 |                  ├↘ button.component.ts
245 |                  │  ↳ styles[0]: `*{}`
246 |                  │  ↳ styles[1]: `*{}`
247 |                  │  ↳ template: `</>`
248 |                  └↘ select.component.ts
249 |                       ├↘ styleUrls[0]: 'select.styles.css'
250 |                       │                ↳ `*{}`
251 |                       ├↘ styleUrls[1]: 'select.styles.css'
252 |                       │                ↳ `*{}`
253 |                       └↘ templateUrl: 'select.component.html''
254 |                                       ↳ `</>`
255 | ```
256 | 
257 | This can potentially be used to filter or add more file to our result file list.
258 | 
259 | ```ts
260 | const tsProgramm = createProgram([
261 |   'src/app/app.component.ts',
262 |   // ...
263 | ]);
264 | 
265 | const components = tsProgramm.getSourceFiles();
266 | ```
267 | 
268 | _components content_
269 | 
270 | ```bash
271 | [ ]
272 |  ├↘ FunctionDeclaration # node_modules/lib/file.js
273 |  ├↘ ClassDeclaration # node_modules/other-lib/other-file.js
274 |  ├↘ VariableDeclaration # node_modules/any-lib/any-file.js
275 |  ├↘ ClassDeclaration # app/app.component.ts
276 |  ├↘ ClassDeclaration # app/ui/button.component.ts
277 |  └↘ ClassDeclaration # app/ui/select.component.ts
278 | ```
279 | 
280 | ### 3. Filtered Components - exclude other files that got added due to existing imports
281 | 
282 | ```ts
283 | components.filter((source) => matchingFiles.includes(source));
284 | ```
285 | 
286 | ```bash
287 | [ ]
288 |  ├↘ ClassDeclaration # app/app.component.ts#AppComponent AST
289 |  ├↘ ClassDeclaration # app/ui/button.component.ts#ButtonComponent AST
290 |  └↘ ClassDeclaration # app/ui/select.component.ts#SelectComponent AST
291 | ```
292 | 
293 | ### 4. Parsed Component Class
294 | 
295 | To go on with creating the Angular component tree we need to get the essential information of every component.
296 | 
297 | We need:
298 | 
299 | - basic component data (file, name, contextual infos)
300 | - the component's AST
301 | - all references to assets (internal as well as external)
302 | - in a step that should be executable lazily we need to resolve the assets
303 | 
304 | As we have to nest different trees here let's quickly define the types that guide us in the future.
305 | 
306 | ```ts
307 | type Unit = {
308 |   type: 'class' | 'html' | 'styles';
309 | };
310 | type Code = {
311 |   filePath: string;
312 |   value: string;
313 | };
314 | type CodeAware = {
315 |   source: <T extends AST>() => T;
316 | };
317 | 
318 | type LinkedCode<T> = Code &
319 |   CodeAware<T> & {
320 |     startLine: string;
321 |   };
322 | 
323 | type Style = LinkedCode<CssAst> & {
324 |   type: 'class';
325 | };
326 | 
327 | type Template = LinkedCode<HtmlAst> & {
328 |   type: 'class';
329 | };
330 | 
331 | type ParsedComponentClass<T> = Code &
332 |   CodeAware<T> & {
333 |     type: 'class';
334 |     className: string;
335 |     styles?: Style[];
336 |     styleUrls?: Style[];
337 |     template?: Template;
338 |     templateUrl?: Template;
339 |   };
340 | ```
341 | 
342 | ```bash
343 | ParsedComponent
344 |  ├╼ className: 'AppComponent`'
345 |  ├╼ filePath: './app.component.ts'
346 |  ├╼ value: `{;}`
347 |  ├╼ source(): TsAst
348 |  │            └↘ ClassDeclaration
349 |  ├╼ styles: [ ]
350 |  │           └╼ [0]: { }
351 |  │                    ├╼ filePath: './app.component.ts'
352 |  │                    ├╼ startLine: 7
353 |  │                    ├╼ value: `*{}`
354 |  │                    └╼ source(): CssAst
355 |  │                                 └↘ RuleContainer
356 |  ├╼ styleUrls: [ ]
357 |  │              └╼ [0]: { }
358 |  │                       ├╼ filePath: './any-styles.css'
359 |  │                       ├╼ startLine: 13
360 |  │                       ├╼ value: `*{}`
361 |  │                       └╼ source(): CssAst
362 |  │                                    └↘ RuleContainer
363 |  ├╼ template: { }
364 |  │             ├╼ filePath: './app.component.ts'
365 |  │             ├╼ startLine: 21
366 |  │             ├╼ value: `</>`
367 |  │             └╼ source(): HtmlAst
368 |  │                          └↘ Element
369 |  └╼ templateUrl: { }
370 |                   ├╼ filePath: './app.component.html'
371 |                   ├╼ startLine: 42
372 |                   ├╼ value: `*{}`
373 |                   └╼ source(): HtmlAst
374 |                                └↘ Element
375 | ```
376 | 
377 | ### 5. Glue Traversal Logic
378 | 
379 | // walk component tree
380 | 
381 | ```ts
382 | const comps: ParsedCompoent[] = getParsedComponents();
383 | 
384 | function walkComponents(node: CodeAware, visitor: T) {
385 |   for (let comp of comps) {
386 |     if ('source' in comp) {
387 |       const unit = comp.source();
388 |       switch (unit.type) {
389 |         case 'class':
390 |           ts.visitAllChildren(unit, visitor as TsVisitor);
391 |         case 'styles':
392 |           walkRules(unit, visitor as CssVisitor);
393 |         case 'html':
394 |           forEachChild(unit, visitor as HtmlVisitor);
395 |       }
396 |     }
397 |   }
398 | }
399 | ```
400 | 
```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/second-case/complex-badge-widget.component.scss:
--------------------------------------------------------------------------------

```scss
  1 | .widget-container {
  2 |   padding: 2rem;
  3 |   background: #f8fafc;
  4 |   border-radius: 0.75rem;
  5 |   box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  6 | }
  7 | 
  8 | .widget-container h3 {
  9 |   margin: 0 0 1.5rem 0;
 10 |   color: #1f2937;
 11 |   font-size: 1.5rem;
 12 |   font-weight: 600;
 13 | }
 14 | 
 15 | .badge-grid {
 16 |   display: grid;
 17 |   grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
 18 |   gap: 1.5rem;
 19 |   margin-bottom: 2rem;
 20 | }
 21 | 
 22 | .badge-item {
 23 |   position: relative;
 24 |   background: white;
 25 |   border-radius: 0.5rem;
 26 |   padding: 1rem;
 27 |   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 28 |   transition: all 0.3s ease;
 29 | }
 30 | 
 31 | .badge-item:hover {
 32 |   transform: translateY(-2px);
 33 |   box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
 34 | }
 35 | 
 36 | // Complex custom badge styles that will be difficult to refactor
 37 | .offer-badge {
 38 |   display: flex;
 39 |   flex-direction: column;
 40 |   background: var(--badge-color, #6b7280);
 41 |   color: white;
 42 |   border-radius: 0.75rem;
 43 |   padding: 0;
 44 |   overflow: hidden;
 45 |   position: relative;
 46 |   cursor: pointer;
 47 |   transition: all 0.3s ease;
 48 |   min-height: 120px;
 49 |   
 50 |   // Complex pseudo-elements that DsBadge won't support
 51 |   &::before {
 52 |     content: '';
 53 |     position: absolute;
 54 |     top: 0;
 55 |     left: 0;
 56 |     right: 0;
 57 |     height: 3px;
 58 |     background: linear-gradient(90deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.8) 50%, rgba(255,255,255,0.3) 100%);
 59 |     animation: shimmer 2s infinite;
 60 |   }
 61 |   
 62 |   &::after {
 63 |     content: attr(data-custom-prop);
 64 |     position: absolute;
 65 |     top: 0.5rem;
 66 |     right: 0.5rem;
 67 |     background: rgba(0, 0, 0, 0.2);
 68 |     padding: 0.25rem 0.5rem;
 69 |     border-radius: 0.25rem;
 70 |     font-size: 0.625rem;
 71 |     font-weight: 600;
 72 |     text-transform: uppercase;
 73 |   }
 74 |   
 75 |   // Level-specific complex styling
 76 |   &.offer-badge-low {
 77 |     background: linear-gradient(135deg, #10b981 0%, #059669 100%);
 78 |     
 79 |     .offer-badge-header {
 80 |       background: rgba(5, 150, 105, 0.2);
 81 |       border-bottom: 2px solid rgba(5, 150, 105, 0.3);
 82 |     }
 83 |     
 84 |     .level-dot.active {
 85 |       background: #34d399;
 86 |       box-shadow: 0 0 8px #34d399;
 87 |     }
 88 |   }
 89 |   
 90 |   &.offer-badge-medium {
 91 |     background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
 92 |     
 93 |     .offer-badge-header {
 94 |       background: rgba(217, 119, 6, 0.2);
 95 |       border-bottom: 2px solid rgba(217, 119, 6, 0.3);
 96 |     }
 97 |     
 98 |     .level-dot.active {
 99 |       background: #fbbf24;
100 |       box-shadow: 0 0 8px #fbbf24;
101 |     }
102 |   }
103 |   
104 |   &.offer-badge-high {
105 |     background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
106 |     
107 |     .offer-badge-header {
108 |       background: rgba(37, 99, 235, 0.2);
109 |       border-bottom: 2px solid rgba(37, 99, 235, 0.3);
110 |     }
111 |     
112 |     .level-dot.active {
113 |       background: #60a5fa;
114 |       box-shadow: 0 0 8px #60a5fa;
115 |     }
116 |   }
117 |   
118 |   &.offer-badge-critical {
119 |     background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
120 |     animation: pulse-critical 2s infinite;
121 |     
122 |     .offer-badge-header {
123 |       background: rgba(220, 38, 38, 0.2);
124 |       border-bottom: 2px solid rgba(220, 38, 38, 0.3);
125 |     }
126 |     
127 |     .level-dot.active {
128 |       background: #f87171;
129 |       box-shadow: 0 0 8px #f87171;
130 |       animation: blink 1s infinite;
131 |     }
132 |   }
133 |   
134 |   // Type-specific complex styling
135 |   &.offer-badge-offer-badge {
136 |     .offer-badge-type-indicator {
137 |       animation: bounce 2s infinite;
138 |     }
139 |     
140 |     .offer-badge-content {
141 |       background: rgba(255, 255, 255, 0.1);
142 |       backdrop-filter: blur(10px);
143 |     }
144 |   }
145 |   
146 |   &.offer-badge-status {
147 |     .offer-badge-header {
148 |       background: linear-gradient(45deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.2) 100%);
149 |     }
150 |     
151 |     .badge-status-indicator {
152 |       width: 12px;
153 |       height: 12px;
154 |       border-radius: 50%;
155 |       background: #10b981;
156 |       animation: pulse-status 1.5s infinite;
157 |     }
158 |   }
159 |   
160 |   &.offer-badge-priority {
161 |     border: 2px solid rgba(255, 255, 255, 0.3);
162 |     
163 |     .offer-badge-type-indicator {
164 |       color: #fbbf24;
165 |       text-shadow: 0 0 8px #fbbf24;
166 |     }
167 |   }
168 |   
169 |   // Interactive states
170 |   &.offer-badge-interactive {
171 |     &:hover {
172 |       transform: scale(1.02);
173 |       box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
174 |       
175 |       .offer-badge-header {
176 |         background: rgba(255, 255, 255, 0.2);
177 |       }
178 |       
179 |       .offer-badge-footer {
180 |         background: rgba(255, 255, 255, 0.1);
181 |       }
182 |     }
183 |     
184 |     &:active {
185 |       transform: scale(0.98);
186 |     }
187 |   }
188 |   
189 |   &.offer-badge-selected {
190 |     border: 3px solid #fbbf24;
191 |     box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.3);
192 |     
193 |     &::before {
194 |       background: linear-gradient(90deg, #fbbf24 0%, #f59e0b 50%, #fbbf24 100%);
195 |     }
196 |   }
197 |   
198 |   // Advanced mode modifications
199 |   &.modified-badge {
200 |     border: 2px dashed rgba(255, 255, 255, 0.5);
201 |     
202 |     .offer-badge-content {
203 |       filter: hue-rotate(30deg);
204 |     }
205 |   }
206 | }
207 | 
208 | // Complex nested structure that DsBadge cannot replicate
209 | .offer-badge-header {
210 |   display: flex;
211 |   justify-content: space-between;
212 |   align-items: center;
213 |   padding: 0.75rem 1rem;
214 |   background: rgba(255, 255, 255, 0.1);
215 |   border-bottom: 1px solid rgba(255, 255, 255, 0.2);
216 |   transition: all 0.3s ease;
217 |   
218 |   &.hover-active {
219 |     background: rgba(255, 255, 255, 0.2);
220 |     transform: translateY(-1px);
221 |   }
222 | }
223 | 
224 | .offer-badge-type-indicator {
225 |   font-size: 1.25rem;
226 |   font-weight: 600;
227 |   display: flex;
228 |   align-items: center;
229 |   gap: 0.5rem;
230 |   
231 |   &::after {
232 |     content: attr(data-type);
233 |     font-size: 0.75rem;
234 |     opacity: 0.8;
235 |   }
236 | }
237 | 
238 | .offer-badge-level-dots {
239 |   display: flex;
240 |   gap: 0.25rem;
241 |   align-items: center;
242 | }
243 | 
244 | .level-dot {
245 |   width: 8px;
246 |   height: 8px;
247 |   border-radius: 50%;
248 |   background: rgba(255, 255, 255, 0.3);
249 |   transition: all 0.3s ease;
250 |   
251 |   &.active {
252 |     background: white;
253 |     box-shadow: 0 0 4px rgba(255, 255, 255, 0.8);
254 |   }
255 | }
256 | 
257 | .offer-badge-content {
258 |   flex: 1;
259 |   padding: 1rem;
260 |   display: flex;
261 |   flex-direction: column;
262 |   justify-content: center;
263 |   position: relative;
264 |   
265 |   &::before {
266 |     content: '';
267 |     position: absolute;
268 |     top: 0;
269 |     left: 0;
270 |     right: 0;
271 |     bottom: 0;
272 |     background: linear-gradient(45deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%);
273 |     pointer-events: none;
274 |   }
275 | }
276 | 
277 | .offer-badge-primary-text {
278 |   font-size: 1.125rem;
279 |   font-weight: 600;
280 |   margin-bottom: 0.5rem;
281 |   text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
282 | }
283 | 
284 | .offer-badge-metadata {
285 |   display: flex;
286 |   flex-direction: column;
287 |   gap: 0.25rem;
288 |   opacity: 0.9;
289 | }
290 | 
291 | .badge-id,
292 | .badge-timestamp {
293 |   font-size: 0.75rem;
294 |   font-weight: 500;
295 |   opacity: 0.8;
296 | }
297 | 
298 | .offer-badge-footer {
299 |   display: flex;
300 |   justify-content: space-between;
301 |   align-items: center;
302 |   padding: 0.75rem 1rem;
303 |   background: rgba(0, 0, 0, 0.1);
304 |   border-top: 1px solid rgba(255, 255, 255, 0.1);
305 |   transition: all 0.3s ease;
306 |   
307 |   &.hover-active {
308 |     background: rgba(0, 0, 0, 0.2);
309 |     transform: translateY(1px);
310 |   }
311 | }
312 | 
313 | .badge-action {
314 |   background: rgba(255, 255, 255, 0.2);
315 |   border: 1px solid rgba(255, 255, 255, 0.3);
316 |   color: white;
317 |   padding: 0.25rem 0.75rem;
318 |   border-radius: 0.25rem;
319 |   font-size: 0.75rem;
320 |   font-weight: 500;
321 |   cursor: pointer;
322 |   transition: all 0.2s ease;
323 |   
324 |   &:hover {
325 |     background: rgba(255, 255, 255, 0.3);
326 |     transform: translateY(-1px);
327 |   }
328 |   
329 |   &.danger {
330 |     background: rgba(239, 68, 68, 0.3);
331 |     border-color: rgba(239, 68, 68, 0.5);
332 |     
333 |     &:hover {
334 |       background: rgba(239, 68, 68, 0.5);
335 |     }
336 |   }
337 | }
338 | 
339 | .badge-status-indicator {
340 |   width: 10px;
341 |   height: 10px;
342 |   border-radius: 50%;
343 |   background: #10b981;
344 |   
345 |   // Dynamic status classes that depend on complex logic
346 |   &.status-low-offer-badge {
347 |     background: #10b981;
348 |     animation: pulse-green 2s infinite;
349 |   }
350 |   
351 |   &.status-medium-status {
352 |     background: #f59e0b;
353 |     animation: pulse-yellow 2s infinite;
354 |   }
355 |   
356 |   &.status-high-priority {
357 |     background: #3b82f6;
358 |     animation: pulse-blue 2s infinite;
359 |   }
360 |   
361 |   &.status-critical-priority {
362 |     background: #ef4444;
363 |     animation: pulse-red 1s infinite;
364 |   }
365 | }
366 | 
367 | // Tooltip system that depends on custom badge structure
368 | .badge-tooltip {
369 |   position: absolute;
370 |   top: 100%;
371 |   left: 50%;
372 |   transform: translateX(-50%);
373 |   background: #1f2937;
374 |   color: white;
375 |   padding: 1rem;
376 |   border-radius: 0.5rem;
377 |   box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
378 |   opacity: 0;
379 |   pointer-events: none;
380 |   transition: all 0.3s ease;
381 |   z-index: 1000;
382 |   min-width: 200px;
383 |   
384 |   &.visible {
385 |     opacity: 1;
386 |     pointer-events: auto;
387 |     transform: translateX(-50%) translateY(0.5rem);
388 |   }
389 |   
390 |   &::before {
391 |     content: '';
392 |     position: absolute;
393 |     top: -8px;
394 |     left: 50%;
395 |     transform: translateX(-50%);
396 |     border-left: 8px solid transparent;
397 |     border-right: 8px solid transparent;
398 |     border-bottom: 8px solid #1f2937;
399 |   }
400 | }
401 | 
402 | .tooltip-content {
403 |   h4 {
404 |     margin: 0 0 0.5rem 0;
405 |     font-size: 1rem;
406 |     font-weight: 600;
407 |   }
408 |   
409 |   p {
410 |     margin: 0 0 0.25rem 0;
411 |     font-size: 0.875rem;
412 |     opacity: 0.9;
413 |   }
414 | }
415 | 
416 | .custom-data {
417 |   margin-top: 0.5rem;
418 |   padding-top: 0.5rem;
419 |   border-top: 1px solid rgba(255, 255, 255, 0.2);
420 | }
421 | 
422 | .data-item {
423 |   font-size: 0.75rem;
424 |   margin-bottom: 0.25rem;
425 |   
426 |   strong {
427 |     color: #fbbf24;
428 |   }
429 | }
430 | 
431 | // Widget controls
432 | .widget-controls {
433 |   display: flex;
434 |   gap: 1rem;
435 |   margin-bottom: 2rem;
436 |   flex-wrap: wrap;
437 |   align-items: center;
438 |   
439 |   button {
440 |     background: #3b82f6;
441 |     color: white;
442 |     border: none;
443 |     padding: 0.5rem 1rem;
444 |     border-radius: 0.375rem;
445 |     font-size: 0.875rem;
446 |     font-weight: 500;
447 |     cursor: pointer;
448 |     transition: all 0.2s ease;
449 |     
450 |     &:hover {
451 |       background: #2563eb;
452 |       transform: translateY(-1px);
453 |     }
454 |   }
455 |   
456 |   label {
457 |     display: flex;
458 |     align-items: center;
459 |     gap: 0.5rem;
460 |     font-size: 0.875rem;
461 |     color: #374151;
462 |     cursor: pointer;
463 |     
464 |     input[type="checkbox"] {
465 |       width: 1rem;
466 |       height: 1rem;
467 |     }
468 |   }
469 | }
470 | 
471 | // Status display
472 | .status-display {
473 |   background: white;
474 |   padding: 1.5rem;
475 |   border-radius: 0.5rem;
476 |   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
477 |   
478 |   h4 {
479 |     margin: 0 0 1rem 0;
480 |     color: #1f2937;
481 |     font-size: 1.125rem;
482 |     font-weight: 600;
483 |   }
484 | }
485 | 
486 | .status-grid {
487 |   display: grid;
488 |   grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
489 |   gap: 1rem;
490 | }
491 | 
492 | .status-item {
493 |   padding: 0.75rem;
494 |   background: #f9fafb;
495 |   border-radius: 0.375rem;
496 |   text-align: center;
497 |   
498 |   strong {
499 |     display: block;
500 |     color: #374151;
501 |     font-size: 0.875rem;
502 |     margin-bottom: 0.25rem;
503 |   }
504 |   
505 |   // Dynamic content that depends on badge counting
506 |   &:nth-child(1) strong::after {
507 |     content: ' 📊';
508 |   }
509 |   
510 |   &:nth-child(2) strong::after {
511 |     content: ' 🎯';
512 |   }
513 |   
514 |   &:nth-child(3) strong::after {
515 |     content: ' ✅';
516 |   }
517 |   
518 |   &:nth-child(4) strong::after {
519 |     content: ' ⚠️';
520 |   }
521 | }
522 | 
523 | // Complex animations that DsBadge won't support
524 | @keyframes shimmer {
525 |   0% { transform: translateX(-100%); }
526 |   100% { transform: translateX(100%); }
527 | }
528 | 
529 | @keyframes pulse-critical {
530 |   0%, 100% { 
531 |     box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7);
532 |   }
533 |   50% { 
534 |     box-shadow: 0 0 0 10px rgba(239, 68, 68, 0);
535 |   }
536 | }
537 | 
538 | @keyframes blink {
539 |   0%, 50% { opacity: 1; }
540 |   51%, 100% { opacity: 0.3; }
541 | }
542 | 
543 | @keyframes bounce {
544 |   0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
545 |   40% { transform: translateY(-4px); }
546 |   60% { transform: translateY(-2px); }
547 | }
548 | 
549 | @keyframes pulse-status {
550 |   0%, 100% { transform: scale(1); opacity: 1; }
551 |   50% { transform: scale(1.2); opacity: 0.7; }
552 | }
553 | 
554 | @keyframes pulse-green {
555 |   0%, 100% { background: #10b981; }
556 |   50% { background: #34d399; }
557 | }
558 | 
559 | @keyframes pulse-yellow {
560 |   0%, 100% { background: #f59e0b; }
561 |   50% { background: #fbbf24; }
562 | }
563 | 
564 | @keyframes pulse-blue {
565 |   0%, 100% { background: #3b82f6; }
566 |   50% { background: #60a5fa; }
567 | }
568 | 
569 | @keyframes pulse-red {
570 |   0%, 100% { background: #ef4444; }
571 |   50% { background: #f87171; }
572 | }
573 | 
574 | // Responsive design with complex badge adaptations
575 | @media (max-width: 768px) {
576 |   .badge-grid {
577 |     grid-template-columns: 1fr;
578 |   }
579 |   
580 |   .offer-badge {
581 |     min-height: 100px;
582 |     
583 |     .offer-badge-header {
584 |       padding: 0.5rem;
585 |     }
586 |     
587 |     .offer-badge-content {
588 |       padding: 0.75rem;
589 |     }
590 |     
591 |     .offer-badge-footer {
592 |       padding: 0.5rem;
593 |     }
594 |     
595 |     .offer-badge-primary-text {
596 |       font-size: 1rem;
597 |     }
598 |     
599 |     // Complex responsive behavior that DsBadge won't handle
600 |     &.offer-badge-critical {
601 |       .offer-badge-type-indicator {
602 |         font-size: 1rem;
603 |       }
604 |       
605 |       .level-dot {
606 |         width: 6px;
607 |         height: 6px;
608 |       }
609 |     }
610 |   }
611 |   
612 |   .widget-controls {
613 |     flex-direction: column;
614 |     align-items: stretch;
615 |     
616 |     button {
617 |       width: 100%;
618 |     }
619 |   }
620 | } 
```

--------------------------------------------------------------------------------
/packages/shared/utils/ai/EXAMPLES.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Examples
  2 | 
  3 | ## 1 — Process execution with real-time monitoring
  4 | 
  5 | > Execute commands with live output streaming and error handling.
  6 | 
  7 | ```ts
  8 | import { executeProcess, ProcessObserver } from '@push-based/utils';
  9 | 
 10 | // Create an observer to handle process events
 11 | const observer: ProcessObserver = {
 12 |   onStdout: (data) => {
 13 |     console.log(`📤 ${data.trim()}`);
 14 |   },
 15 |   onStderr: (data) => {
 16 |     console.error(`❌ ${data.trim()}`);
 17 |   },
 18 |   onError: (error) => {
 19 |     console.error(`Process failed with code ${error.code}`);
 20 |   },
 21 |   onComplete: () => {
 22 |     console.log('✅ Process completed successfully');
 23 |   },
 24 | };
 25 | 
 26 | // Execute a Node.js command
 27 | const result = await executeProcess({
 28 |   command: 'node',
 29 |   args: ['--version'],
 30 |   observer,
 31 | });
 32 | 
 33 | console.log(`Exit code: ${result.code}`);
 34 | console.log(`Duration: ${result.duration}ms`);
 35 | console.log(`Output: ${result.stdout.trim()}`);
 36 | 
 37 | // Output:
 38 | // → 📤 v18.17.0
 39 | // → ✅ Process completed successfully
 40 | // → Exit code: 0
 41 | // → Duration: 45ms
 42 | // → Output: v18.17.0
 43 | ```
 44 | 
 45 | ---
 46 | 
 47 | ## 2 — File pattern searching and processing
 48 | 
 49 | > Search for files containing specific patterns and process the results.
 50 | 
 51 | ```ts
 52 | import {
 53 |   findFilesWithPattern,
 54 |   findInFile,
 55 |   resolveFileCached,
 56 | } from '@push-based/utils';
 57 | 
 58 | // Find all TypeScript files containing 'Component'
 59 | const componentFiles = await findFilesWithPattern('./src', 'Component');
 60 | 
 61 | console.log(`Found ${componentFiles.length} files with 'Component':`);
 62 | componentFiles.forEach((file) => console.log(`  - ${file}`));
 63 | 
 64 | // Get detailed information about matches in a specific file
 65 | if (componentFiles.length > 0) {
 66 |   const firstFile = componentFiles[0];
 67 |   const matches = await findInFile(firstFile, 'Component');
 68 | 
 69 |   console.log(`\nDetailed matches in ${firstFile}:`);
 70 |   matches.forEach((match) => {
 71 |     console.log(
 72 |       `  Line ${match.position.startLine}, Column ${match.position.startColumn}`
 73 |     );
 74 |   });
 75 | 
 76 |   // Load and cache the file content
 77 |   const content = await resolveFileCached(firstFile);
 78 |   console.log(`File size: ${content.length} characters`);
 79 | 
 80 |   // Subsequent calls will use cached version
 81 |   const cachedContent = await resolveFileCached(firstFile); // ⚡ Fast cached access
 82 | }
 83 | 
 84 | // Output:
 85 | // → Found 3 files with 'Component':
 86 | // →   - ./src/app/user.component.ts
 87 | // →   - ./src/app/admin.component.ts
 88 | // →   - ./src/shared/base.component.ts
 89 | // →
 90 | // → Detailed matches in ./src/app/user.component.ts:
 91 | // →   Line 5, Column 14
 92 | // →   Line 12, Column 25
 93 | // → File size: 1247 characters
 94 | ```
 95 | 
 96 | ---
 97 | 
 98 | ## 3 — Command formatting and logging
 99 | 
100 | > Format commands with colors and context for better development experience.
101 | 
102 | ```ts
103 | import { formatCommandLog, isVerbose, calcDuration } from '@push-based/utils';
104 | 
105 | // Set verbose mode for demonstration
106 | process.env['NG_MCP_VERBOSE'] = 'true';
107 | 
108 | // Format commands with different contexts
109 | const commands = [
110 |   { cmd: 'npm', args: ['install'], cwd: undefined },
111 |   { cmd: 'npx', args: ['eslint', '--fix', 'src/'], cwd: './packages/app' },
112 |   { cmd: 'node', args: ['build.js', '--prod'], cwd: '../tools' },
113 |   {
114 |     cmd: 'git',
115 |     args: ['commit', '-m', 'feat: add new feature'],
116 |     cwd: process.cwd(),
117 |   },
118 | ];
119 | 
120 | console.log('Formatted commands:');
121 | commands.forEach(({ cmd, args, cwd }) => {
122 |   const formatted = formatCommandLog(cmd, args, cwd);
123 |   console.log(formatted);
124 | });
125 | 
126 | // Performance timing example
127 | async function timedOperation() {
128 |   const start = performance.now();
129 | 
130 |   // Simulate some work
131 |   await new Promise((resolve) => setTimeout(resolve, 150));
132 | 
133 |   const duration = calcDuration(start);
134 |   console.log(`Operation completed in ${duration}ms`);
135 | }
136 | 
137 | // Verbose logging check
138 | if (isVerbose()) {
139 |   console.log('🔍 Verbose logging is enabled');
140 |   await timedOperation();
141 | } else {
142 |   console.log('🔇 Verbose logging is disabled');
143 | }
144 | 
145 | // Output (with ANSI colors in terminal):
146 | // → Formatted commands:
147 | // → $ npm install
148 | // → packages/app $ npx eslint --fix src/
149 | // → .. $ node build.js --prod
150 | // → $ git commit -m feat: add new feature
151 | // → 🔍 Verbose logging is enabled
152 | // → Operation completed in 152ms
153 | ```
154 | 
155 | ---
156 | 
157 | ## 4 — CLI argument generation
158 | 
159 | > Convert objects to command-line arguments for process execution.
160 | 
161 | ```ts
162 | import { objectToCliArgs, executeProcess } from '@push-based/utils';
163 | 
164 | // Simple configuration object
165 | const config = {
166 |   _: ['npx', 'eslint'], // Command and base args
167 |   fix: true, // Boolean flag
168 |   format: 'json', // String value
169 |   ext: ['.ts', '.js'], // Array values
170 |   'max-warnings': 0, // Numeric value
171 |   quiet: false, // Negative boolean
172 | };
173 | 
174 | const args = objectToCliArgs(config);
175 | console.log('Generated CLI args:');
176 | args.forEach((arg) => console.log(`  ${arg}`));
177 | 
178 | // Use the generated arguments in process execution
179 | const result = await executeProcess({
180 |   command: args[0], // 'npx'
181 |   args: args.slice(1), // Everything after the command
182 | });
183 | 
184 | // Output:
185 | // → Generated CLI args:
186 | // →   npx
187 | // →   eslint
188 | // →   --fix
189 | // →   --format="json"
190 | // →   --ext=".ts"
191 | // →   --ext=".js"
192 | // →   --max-warnings=0
193 | // →   --no-quiet
194 | 
195 | // Complex nested configuration
196 | const complexConfig = {
197 |   _: ['node', 'build.js'],
198 |   output: {
199 |     path: './dist',
200 |     format: 'esm',
201 |   },
202 |   optimization: {
203 |     minify: true,
204 |     'tree-shake': true,
205 |   },
206 | };
207 | 
208 | const complexArgs = objectToCliArgs(complexConfig);
209 | console.log('\nComplex nested args:');
210 | complexArgs.forEach((arg) => console.log(`  ${arg}`));
211 | 
212 | // Output:
213 | // → Complex nested args:
214 | // →   node
215 | // →   build.js
216 | // →   --output.path="./dist"
217 | // →   --output.format="esm"
218 | // →   --optimization.minify
219 | // →   --optimization.tree-shake
220 | ```
221 | 
222 | ---
223 | 
224 | ## 5 — Error handling and process management
225 | 
226 | > Handle process errors gracefully with comprehensive error information.
227 | 
228 | ```ts
229 | import { executeProcess, ProcessError } from '@push-based/utils';
230 | 
231 | async function robustProcessExecution() {
232 |   const commands = [
233 |     { command: 'node', args: ['--version'] }, // ✅ Should succeed
234 |     { command: 'nonexistent-command', args: [] }, // ❌ Should fail
235 |     { command: 'node', args: ['-e', 'process.exit(1)'] }, // ❌ Should fail with exit code 1
236 |   ];
237 | 
238 |   for (const config of commands) {
239 |     try {
240 |       console.log(
241 |         `\n🚀 Executing: ${config.command} ${config.args?.join(' ') || ''}`
242 |       );
243 | 
244 |       const result = await executeProcess({
245 |         ...config,
246 |         observer: {
247 |           onStdout: (data) => console.log(`  📤 ${data.trim()}`),
248 |           onStderr: (data) => console.error(`  ❌ ${data.trim()}`),
249 |           onComplete: () => console.log('  ✅ Process completed'),
250 |         },
251 |       });
252 | 
253 |       console.log(
254 |         `  ✅ Success! Exit code: ${result.code}, Duration: ${result.duration}ms`
255 |       );
256 |     } catch (error) {
257 |       if (error instanceof ProcessError) {
258 |         console.error(`  ❌ Process failed:`);
259 |         console.error(`     Exit code: ${error.code}`);
260 |         console.error(
261 |           `     Error output: ${error.stderr.trim() || 'No stderr'}`
262 |         );
263 |         console.error(
264 |           `     Standard output: ${error.stdout.trim() || 'No stdout'}`
265 |         );
266 |       } else {
267 |         console.error(`  ❌ Unexpected error: ${error}`);
268 |       }
269 |     }
270 |   }
271 | 
272 |   // Example with ignoreExitCode option
273 |   console.log('\n🔄 Executing command with ignoreExitCode=true:');
274 |   try {
275 |     const result = await executeProcess({
276 |       command: 'node',
277 |       args: ['-e', 'console.log("Hello"); process.exit(1)'],
278 |       ignoreExitCode: true,
279 |       observer: {
280 |         onStdout: (data) => console.log(`  📤 ${data.trim()}`),
281 |         onComplete: () =>
282 |           console.log('  ✅ Process completed (exit code ignored)'),
283 |       },
284 |     });
285 | 
286 |     console.log(`  ✅ Completed with exit code ${result.code} (ignored)`);
287 |     console.log(`  📝 Output: ${result.stdout.trim()}`);
288 |   } catch (error) {
289 |     console.error(`  ❌ This shouldn't happen with ignoreExitCode=true`);
290 |   }
291 | }
292 | 
293 | await robustProcessExecution();
294 | 
295 | // Output:
296 | // → 🚀 Executing: node --version
297 | // →   📤 v18.17.0
298 | // →   ✅ Process completed
299 | // →   ✅ Success! Exit code: 0, Duration: 42ms
300 | // →
301 | // → 🚀 Executing: nonexistent-command
302 | // →   ❌ Process failed:
303 | // →      Exit code: null
304 | // →      Error output: spawn nonexistent-command ENOENT
305 | // →      Standard output: No stdout
306 | // →
307 | // → 🚀 Executing: node -e process.exit(1)
308 | // →   ❌ Process failed:
309 | // →      Exit code: 1
310 | // →      Error output: No stderr
311 | // →      Standard output: No stdout
312 | // →
313 | // → 🔄 Executing command with ignoreExitCode=true:
314 | // →   📤 Hello
315 | // →   ✅ Process completed (exit code ignored)
316 | // →   ✅ Completed with exit code 1 (ignored)
317 | // →   📝 Output: Hello
318 | ```
319 | 
320 | ---
321 | 
322 | ## 6 — Advanced file operations with generators
323 | 
324 | > Use async generators for efficient file processing.
325 | 
326 | ```ts
327 | import {
328 |   findAllFiles,
329 |   accessContent,
330 |   getLineHits,
331 |   isExcludedDirectory,
332 | } from '@push-based/utils';
333 | 
334 | // Custom file finder with filtering
335 | async function findLargeTypeScriptFiles(
336 |   baseDir: string,
337 |   minSize: number = 1000
338 | ) {
339 |   const largeFiles: string[] = [];
340 | 
341 |   // Use async generator to process files one by one
342 |   for await (const file of findAllFiles(baseDir, (path) =>
343 |     path.endsWith('.ts')
344 |   )) {
345 |     try {
346 |       const stats = await fs.stat(file);
347 |       if (stats.size > minSize) {
348 |         largeFiles.push(file);
349 |         console.log(`📁 Large file: ${file} (${stats.size} bytes)`);
350 |       }
351 |     } catch (error) {
352 |       console.warn(`⚠️  Could not stat file: ${file}`);
353 |     }
354 |   }
355 | 
356 |   return largeFiles;
357 | }
358 | 
359 | // Process file content line by line
360 | async function analyzeFileContent(filePath: string, searchTerm: string) {
361 |   const content = await fs.readFile(filePath, 'utf-8');
362 |   const results = {
363 |     totalLines: 0,
364 |     matchingLines: 0,
365 |     matches: [] as Array<{ line: number; hits: number; content: string }>,
366 |   };
367 | 
368 |   // Use generator to process content efficiently
369 |   let lineNumber = 0;
370 |   for (const line of accessContent(content)) {
371 |     lineNumber++;
372 |     results.totalLines++;
373 | 
374 |     const hits = getLineHits(line, searchTerm);
375 |     if (hits.length > 0) {
376 |       results.matchingLines++;
377 |       results.matches.push({
378 |         line: lineNumber,
379 |         hits: hits.length,
380 |         content: line.trim(),
381 |       });
382 |     }
383 |   }
384 | 
385 |   return results;
386 | }
387 | 
388 | // Directory filtering
389 | const directories = [
390 |   'src',
391 |   '.git',
392 |   'node_modules',
393 |   'dist',
394 |   'coverage',
395 |   '.vscode',
396 | ];
397 | directories.forEach((dir) => {
398 |   const excluded = isExcludedDirectory(dir);
399 |   console.log(`${dir}: ${excluded ? '❌ excluded' : '✅ included'}`);
400 | });
401 | 
402 | // Usage example
403 | const largeFiles = await findLargeTypeScriptFiles('./src', 2000);
404 | if (largeFiles.length > 0) {
405 |   const analysis = await analyzeFileContent(largeFiles[0], 'export');
406 |   console.log(`\nAnalysis of ${largeFiles[0]}:`);
407 |   console.log(`Total lines: ${analysis.totalLines}`);
408 |   console.log(`Lines with 'export': ${analysis.matchingLines}`);
409 |   console.log(`First few matches:`);
410 |   analysis.matches.slice(0, 3).forEach((match) => {
411 |     console.log(`  Line ${match.line} (${match.hits} hits): ${match.content}`);
412 |   });
413 | }
414 | 
415 | // Output:
416 | // → src: ✅ included
417 | // → .git: ❌ excluded
418 | // → node_modules: ❌ excluded
419 | // → dist: ❌ excluded
420 | // → coverage: ❌ excluded
421 | // → .vscode: ✅ included
422 | // → 📁 Large file: ./src/lib/utils.ts (2247 bytes)
423 | // → 📁 Large file: ./src/lib/execute-process.ts (5043 bytes)
424 | // →
425 | // → Analysis of ./src/lib/utils.ts:
426 | // → Total lines: 88
427 | // → Lines with 'export': 5
428 | // → First few matches:
429 | // →   Line 2 (1 hits): export function calcDuration(start: number, stop?: number): number {
430 | // →   Line 6 (1 hits): export function isVerbose(): boolean {
431 | // →   Line 14 (1 hits): export function formatCommandLog(command: string, args?: string[], cwd?: string): string {
432 | ```
433 | 
434 | ---
435 | 
436 | ## 7 — ES Module loading and dynamic imports
437 | 
438 | > Load ES modules dynamically and extract default exports safely.
439 | 
440 | ```ts
441 | import { loadDefaultExport } from '@push-based/utils';
442 | 
443 | // Load configuration from ES module
444 | const config = await loadDefaultExport('./config/app.config.mjs');
445 | console.log(`API Port: ${config.port}`);
446 | 
447 | // Load with type safety
448 | interface AppData {
449 |   version: string;
450 |   features: string[];
451 | }
452 | 
453 | const appData = await loadDefaultExport<AppData>('./data/app.mjs');
454 | console.log(`App version: ${appData.version}`);
455 | console.log(`Features: ${appData.features.join(', ')}`);
456 | 
457 | // Handle loading errors gracefully
458 | try {
459 |   const plugin = await loadDefaultExport('./plugins/optional.mjs');
460 |   console.log('✅ Plugin loaded');
461 | } catch (error) {
462 |   if (error.message.includes('No default export found')) {
463 |     console.warn('⚠️  Module missing default export');
464 |   } else {
465 |     console.warn('⚠️  Plugin not found, continuing without it');
466 |   }
467 | }
468 | 
469 | // Output:
470 | // → API Port: 3000
471 | // → App version: 1.2.0  
472 | // → Features: auth, logging, metrics
473 | // → ⚠️  Plugin not found, continuing without it
474 | ```
475 | 
476 | ---
477 | 
478 | 
479 | 
480 | These examples demonstrate the comprehensive capabilities of the `@push-based/utils` library for process execution, file operations, string manipulation, and development tooling in Node.js applications.
481 | 
```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/second-case/complex-badge-widget.component.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import {
  2 |   ChangeDetectionStrategy,
  3 |   Component,
  4 |   ElementRef,
  5 |   ViewEncapsulation,
  6 |   computed,
  7 |   input,
  8 |   output,
  9 |   signal,
 10 |   booleanAttribute,
 11 |   OnInit,
 12 |   OnDestroy,
 13 |   inject,
 14 |   Renderer2,
 15 | } from '@angular/core';
 16 | import { CommonModule } from '@angular/common';
 17 | import { FormsModule } from '@angular/forms';
 18 | 
 19 | export interface BadgeConfig {
 20 |   id: string;
 21 |   text: string;
 22 |   type: 'offer-badge' | 'status' | 'priority';
 23 |   level: 'low' | 'medium' | 'high' | 'critical';
 24 |   interactive: boolean;
 25 |   customData: Record<string, any>;
 26 | }
 27 | 
 28 | @Component({
 29 |   selector: 'app-complex-badge-widget',
 30 |   standalone: true,
 31 |   imports: [CommonModule, FormsModule],
 32 |   template: `
 33 |     <div class="widget-container">
 34 |       <h3>Complex Badge Widget</h3>
 35 |       
 36 |       <!-- This component relies heavily on custom badge structure that will break -->
 37 |       <div class="badge-grid">
 38 |         @for (badge of badges(); track badge.id) {
 39 |           <div class="badge-item" [attr.data-badge-id]="badge.id">
 40 |             <!-- Complex custom badge with nested structure -->
 41 |             <div 
 42 |               class="offer-badge offer-badge-{{ badge.level }} offer-badge-{{ badge.type }}"
 43 |               [class.offer-badge-interactive]="badge.interactive"
 44 |               [class.offer-badge-selected]="isSelected(badge.id)"
 45 |               (click)="toggleBadge(badge.id)"
 46 |               [attr.data-custom-prop]="badge.customData.prop"
 47 |               [style.--badge-color]="getBadgeColor(badge.level)">
 48 |               
 49 |               <!-- This structure is incompatible with DsBadge slots -->
 50 |               <div class="offer-badge-header">
 51 |                 <span class="offer-badge-type-indicator">{{ getTypeIcon(badge.type) }}</span>
 52 |                 <div class="offer-badge-level-dots">
 53 |                   @for (dot of getLevelDots(badge.level); track $index) {
 54 |                     <span class="level-dot" [class.active]="dot"></span>
 55 |                   }
 56 |                 </div>
 57 |               </div>
 58 |               
 59 |               <!-- Main content with complex nested structure -->
 60 |               <div class="offer-badge-content">
 61 |                 <div class="offer-badge-primary-text">{{ badge.text }}</div>
 62 |                 <div class="offer-badge-metadata">
 63 |                   <span class="badge-id">ID: {{ badge.id }}</span>
 64 |                   <span class="badge-timestamp">{{ getTimestamp() }}</span>
 65 |                 </div>
 66 |               </div>
 67 |               
 68 |               <!-- Footer with actions - incompatible with DsBadge -->
 69 |               <div class="offer-badge-footer">
 70 |                 @if (badge.interactive) {
 71 |                   <button class="badge-action" (click)="editBadge($event, badge.id)">Edit</button>
 72 |                   <button class="badge-action danger" (click)="deleteBadge($event, badge.id)">×</button>
 73 |                 }
 74 |                 <div class="badge-status-indicator" [class]="getStatusClass(badge)"></div>
 75 |               </div>
 76 |             </div>
 77 |             
 78 |             <!-- Additional complex elements that depend on custom structure -->
 79 |             <div class="badge-tooltip" [class.visible]="showTooltip() === badge.id">
 80 |               <div class="tooltip-content">
 81 |                 <h4>{{ badge.text }}</h4>
 82 |                 <p>Type: {{ badge.type }}</p>
 83 |                 <p>Level: {{ badge.level }}</p>
 84 |                 <div class="custom-data">
 85 |                   @for (item of getCustomDataEntries(badge.customData); track item.key) {
 86 |                     <div class="data-item">
 87 |                       <strong>{{ item.key }}:</strong> {{ item.value }}
 88 |                     </div>
 89 |                   }
 90 |                 </div>
 91 |               </div>
 92 |             </div>
 93 |           </div>
 94 |         }
 95 |       </div>
 96 |       
 97 |       <!-- Controls that manipulate badge structure directly -->
 98 |       <div class="widget-controls">
 99 |         <button (click)="addRandomBadge()">Add Random Badge</button>
100 |         <button (click)="modifyAllBadges()">Modify All Badges</button>
101 |         <button (click)="resetBadges()">Reset</button>
102 |         <label>
103 |           <input type="checkbox" [(ngModel)]="enableAdvancedMode" (change)="onAdvancedModeChange()">
104 |           Advanced Mode (manipulates DOM directly)
105 |         </label>
106 |       </div>
107 |       
108 |       <!-- Status display that reads from custom badge elements -->
109 |       <div class="status-display">
110 |         <h4>Status Summary:</h4>
111 |         <div class="status-grid">
112 |           <div class="status-item">
113 |             <strong>Total Badges:</strong> {{ badges().length }}
114 |           </div>
115 |           <div class="status-item">
116 |             <strong>Interactive:</strong> {{ getInteractiveBadgesCount() }}
117 |           </div>
118 |           <div class="status-item">
119 |             <strong>Selected:</strong> {{ selectedBadges().length }}
120 |           </div>
121 |           <div class="status-item">
122 |             <strong>Critical Level:</strong> {{ getCriticalBadgesCount() }}
123 |           </div>
124 |         </div>
125 |       </div>
126 |     </div>
127 |   `,
128 |   styleUrls: ['./complex-badge-widget.component.scss'],
129 |   encapsulation: ViewEncapsulation.None,
130 |   changeDetection: ChangeDetectionStrategy.OnPush,
131 | })
132 | export class ComplexBadgeWidgetComponent implements OnInit, OnDestroy {
133 |   // Inputs
134 |   initialBadges = input<BadgeConfig[]>([]);
135 |   enableAdvancedMode = signal(false);
136 |   showTooltip = signal<string | null>(null);
137 |   
138 |   // Outputs
139 |   badgeSelected = output<string>();
140 |   badgeModified = output<BadgeConfig>();
141 |   badgeDeleted = output<string>();
142 |   
143 |   // Internal state
144 |   badges = signal<BadgeConfig[]>([]);
145 |   selectedBadges = signal<string[]>([]);
146 |   
147 |   private elementRef = inject(ElementRef);
148 |   private renderer = inject(Renderer2);
149 |   private badgeCounter = 0;
150 | 
151 |   ngOnInit() {
152 |     this.initializeBadges();
153 |     this.setupAdvancedModeObserver();
154 |   }
155 | 
156 |   ngOnDestroy() {
157 |     // Cleanup
158 |   }
159 | 
160 |   private initializeBadges() {
161 |     const defaultBadges: BadgeConfig[] = [
162 |       {
163 |         id: 'badge-1',
164 |         text: 'Premium Offer',
165 |         type: 'offer-badge',
166 |         level: 'high',
167 |         interactive: true,
168 |         customData: { prop: 'premium', priority: 1, category: 'sales' }
169 |       },
170 |       {
171 |         id: 'badge-2',
172 |         text: 'System Status',
173 |         type: 'status',
174 |         level: 'medium',
175 |         interactive: false,
176 |         customData: { prop: 'status', health: 'good', uptime: '99.9%' }
177 |       },
178 |       {
179 |         id: 'badge-3',
180 |         text: 'Critical Alert',
181 |         type: 'priority',
182 |         level: 'critical',
183 |         interactive: true,
184 |         customData: { prop: 'alert', severity: 'high', source: 'monitoring' }
185 |       }
186 |     ];
187 |     
188 |     this.badges.set(this.initialBadges().length > 0 ? this.initialBadges() : defaultBadges);
189 |   }
190 | 
191 |   private setupAdvancedModeObserver() {
192 |     // This method directly manipulates DOM elements in a way that will break with DsBadge
193 |     // because it expects specific custom badge structure
194 |   }
195 | 
196 |   // Methods that rely on custom badge structure
197 |   getBadgeColor(level: string): string {
198 |     const colorMap: Record<string, string> = {
199 |       'low': '#10b981',
200 |       'medium': '#f59e0b', 
201 |       'high': '#3b82f6',
202 |       'critical': '#ef4444'
203 |     };
204 |     return colorMap[level] || '#6b7280';
205 |   }
206 | 
207 |   getTypeIcon(type: string): string {
208 |     const iconMap: Record<string, string> = {
209 |       'offer-badge': '🎯',
210 |       'status': '📊',
211 |       'priority': '⚠️'
212 |     };
213 |     return iconMap[type] || '📌';
214 |   }
215 | 
216 |   getLevelDots(level: string): boolean[] {
217 |     const dotMap: Record<string, boolean[]> = {
218 |       'low': [true, false, false],
219 |       'medium': [true, true, false],
220 |       'high': [true, true, true],
221 |       'critical': [true, true, true]
222 |     };
223 |     return dotMap[level] || [false, false, false];
224 |   }
225 | 
226 |   getStatusClass(badge: BadgeConfig): string {
227 |     return `status-${badge.level}-${badge.type}`;
228 |   }
229 | 
230 |   getCustomDataEntries(customData: Record<string, any>): Array<{key: string, value: any}> {
231 |     return Object.entries(customData).map(([key, value]) => ({ key, value }));
232 |   }
233 | 
234 |   getTimestamp(): string {
235 |     return new Date().toLocaleTimeString();
236 |   }
237 | 
238 |   // Interactive methods that depend on custom structure
239 |   isSelected(badgeId: string): boolean {
240 |     return this.selectedBadges().includes(badgeId);
241 |   }
242 | 
243 |   toggleBadge(badgeId: string) {
244 |     const selected = this.selectedBadges();
245 |     if (selected.includes(badgeId)) {
246 |       this.selectedBadges.set(selected.filter(id => id !== badgeId));
247 |     } else {
248 |       this.selectedBadges.set([...selected, badgeId]);
249 |     }
250 |     this.badgeSelected.emit(badgeId);
251 |   }
252 | 
253 |   editBadge(event: Event, badgeId: string) {
254 |     event.stopPropagation();
255 |     const badge = this.badges().find(b => b.id === badgeId);
256 |     if (badge) {
257 |       // Simulate editing
258 |       const updatedBadge = { ...badge, text: badge.text + ' (edited)' };
259 |       this.updateBadge(updatedBadge);
260 |       this.badgeModified.emit(updatedBadge);
261 |     }
262 |   }
263 | 
264 |   deleteBadge(event: Event, badgeId: string) {
265 |     event.stopPropagation();
266 |     this.badges.set(this.badges().filter(b => b.id !== badgeId));
267 |     this.selectedBadges.set(this.selectedBadges().filter(id => id !== badgeId));
268 |     this.badgeDeleted.emit(badgeId);
269 |   }
270 | 
271 |   addRandomBadge() {
272 |     this.badgeCounter++;
273 |     const types: BadgeConfig['type'][] = ['offer-badge', 'status', 'priority'];
274 |     const levels: BadgeConfig['level'][] = ['low', 'medium', 'high', 'critical'];
275 |     
276 |     const newBadge: BadgeConfig = {
277 |       id: `badge-${Date.now()}-${this.badgeCounter}`,
278 |       text: `Dynamic Badge ${this.badgeCounter}`,
279 |       type: types[Math.floor(Math.random() * types.length)],
280 |       level: levels[Math.floor(Math.random() * levels.length)],
281 |       interactive: Math.random() > 0.5,
282 |       customData: { 
283 |         prop: `dynamic-${this.badgeCounter}`, 
284 |         generated: true,
285 |         timestamp: Date.now()
286 |       }
287 |     };
288 |     
289 |     this.badges.set([...this.badges(), newBadge]);
290 |   }
291 | 
292 |   modifyAllBadges() {
293 |     // This method directly manipulates DOM to demonstrate breaking changes
294 |     if (this.enableAdvancedMode()) {
295 |       const badgeElements = this.elementRef.nativeElement.querySelectorAll('.offer-badge');
296 |       badgeElements.forEach((element: HTMLElement, index: number) => {
297 |         // Direct DOM manipulation that will break with DsBadge
298 |         const contentDiv = element.querySelector('.offer-badge-content');
299 |         if (contentDiv) {
300 |           this.renderer.setStyle(contentDiv, 'transform', `rotate(${index * 2}deg)`);
301 |           this.renderer.addClass(element, 'modified-badge');
302 |         }
303 |         
304 |         // Add custom attributes that DsBadge won't support
305 |         this.renderer.setAttribute(element, 'data-modification-time', Date.now().toString());
306 |         this.renderer.setAttribute(element, 'data-custom-behavior', 'advanced');
307 |       });
308 |     }
309 |   }
310 | 
311 |   resetBadges() {
312 |     this.initializeBadges();
313 |     this.selectedBadges.set([]);
314 |     this.showTooltip.set(null);
315 |     
316 |     // Reset DOM modifications
317 |     const badgeElements = this.elementRef.nativeElement.querySelectorAll('.offer-badge');
318 |     badgeElements.forEach((element: HTMLElement) => {
319 |       this.renderer.removeStyle(element, 'transform');
320 |       this.renderer.removeClass(element, 'modified-badge');
321 |       this.renderer.removeAttribute(element, 'data-modification-time');
322 |       this.renderer.removeAttribute(element, 'data-custom-behavior');
323 |     });
324 |   }
325 | 
326 |   onAdvancedModeChange() {
327 |     if (this.enableAdvancedMode()) {
328 |       // Enable advanced DOM manipulation features
329 |       this.setupAdvancedBehaviors();
330 |     } else {
331 |       this.resetBadges();
332 |     }
333 |   }
334 | 
335 |   private setupAdvancedBehaviors() {
336 |     // This method sets up behaviors that depend on custom badge DOM structure
337 |     // and will break when using DsBadge
338 |     setTimeout(() => {
339 |       const badgeElements = this.elementRef.nativeElement.querySelectorAll('.offer-badge');
340 |       badgeElements.forEach((element: HTMLElement) => {
341 |         // Add hover effects that depend on custom structure
342 |         element.addEventListener('mouseenter', () => {
343 |           const header = element.querySelector('.offer-badge-header');
344 |           const footer = element.querySelector('.offer-badge-footer');
345 |           if (header && footer) {
346 |             this.renderer.addClass(header, 'hover-active');
347 |             this.renderer.addClass(footer, 'hover-active');
348 |           }
349 |         });
350 |         
351 |         element.addEventListener('mouseleave', () => {
352 |           const header = element.querySelector('.offer-badge-header');
353 |           const footer = element.querySelector('.offer-badge-footer');
354 |           if (header && footer) {
355 |             this.renderer.removeClass(header, 'hover-active');
356 |             this.renderer.removeClass(footer, 'hover-active');
357 |           }
358 |         });
359 |       });
360 |     }, 100);
361 |   }
362 | 
363 |   private updateBadge(updatedBadge: BadgeConfig) {
364 |     const badges = this.badges();
365 |     const index = badges.findIndex(b => b.id === updatedBadge.id);
366 |     if (index !== -1) {
367 |       badges[index] = updatedBadge;
368 |       this.badges.set([...badges]);
369 |     }
370 |   }
371 | 
372 |   // Computed values that depend on custom badge structure
373 |   getInteractiveBadgesCount(): number {
374 |     return this.badges().filter(b => b.interactive).length;
375 |   }
376 | 
377 |   getCriticalBadgesCount(): number {
378 |     return this.badges().filter(b => b.level === 'critical').length;
379 |   }
380 | } 
```

--------------------------------------------------------------------------------
/docs/component-refactoring-flow.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Component Refactoring Flow
  2 | 
  3 | ## Overview
  4 | 
  5 | This document describes a 3-step AI-assisted component refactoring process for improving individual Angular components according to modern best practices. Each step uses a specific rule file (.mdc) that guides the Cursor agent through systematic analysis, code improvements, and validation.
  6 | 
  7 | **Process Summary:**
  8 | 1. **Review Component** → Analyze component against best practices and create improvement plan
  9 | 2. **Refactor Component** → Execute approved checklist items and implement changes
 10 | 3. **Validate Component** → Verify improvements through contract comparison and scoring
 11 | 
 12 | The process includes two quality gates where human review and approval are required. When refactoring involves Design System components, the process can leverage selective data retrieval to access only the specific component information needed (implementation, documentation, or stories).
 13 | 
 14 | ## Prerequisites
 15 | 
 16 | Before starting the component refactoring flow, ensure you have:
 17 | - Cursor IDE with this MCP (Model Context Protocol) server connected. This flow was tested with Cursor but should also work with Windsurf or Copilot.
 18 | - The three rule files (.mdc) available in your workspace
 19 | - A git branch for the refactoring work
 20 | - The component files (TypeScript, template, and styles) accessible in your workspace
 21 | 
 22 | ## 01-review-component.mdc
 23 | 
 24 | ### Goal
 25 | 
 26 | Analyze an Angular component against modern best practices and design system guidelines to create a comprehensive improvement plan. This rule evaluates component quality across five key dimensions and generates an actionable refactoring checklist.
 27 | 
 28 | ### Process
 29 | 
 30 | To start this process, drag file `01-review-component.mdc` to the cursor chat and provide the required parameters:
 31 | 
 32 | ```
 33 | component_path=path/to/component.ts
 34 | styleguide="Angular 20 best practices with signals, standalone components, and modern control flow"
 35 | component_files=[provide the TypeScript, template, and style file contents]
 36 | 
 37 | @01-review-component.mdc
 38 | ```
 39 | 
 40 | This rule follows a structured analysis process:
 41 | 
 42 | **Step 1: File Validation**
 43 | - Verifies all essential component files are provided (TypeScript, template, styles)
 44 | - Ensures component structure is complete for analysis
 45 | - Stops process if critical files are missing
 46 | 
 47 | **Step 2: Multi-Dimensional Analysis**
 48 | - Evaluates component against five key categories:
 49 |   - **Accessibility**: ARIA attributes, semantic HTML, keyboard navigation
 50 |   - **Performance**: Change detection strategy, lazy loading, bundle size impact
 51 |   - **Scalability**: Code organization, reusability, maintainability patterns
 52 |   - **Maintainability**: Code clarity, documentation, testing considerations
 53 |   - **Best Practices**: Angular conventions, TypeScript usage, modern patterns
 54 | 
 55 | **Step 3: Scoring and Assessment**
 56 | - Assigns numerical scores (1-10) for each category
 57 | - Identifies 3-5 concrete observations per category
 58 | - Provides narrative analysis of overall component state
 59 | 
 60 | **Step 4: Checklist Generation**
 61 | - Creates actionable improvement items based on analysis
 62 | - Prioritizes changes by impact and complexity
 63 | - Formats as markdown checklist for systematic execution
 64 | 
 65 | ---
 66 | **🚦 Quality Gate 1**
 67 | 
 68 | Before proceeding to implementation, you must review and approve the refactoring plan.
 69 | 
 70 | **Required Actions:**
 71 | - Review the component analysis and scores
 72 | - Examine the proposed refactoring checklist
 73 | - Approve the plan or request modifications
 74 | 
 75 | **Next Step:** When satisfied with the checklist, attach the next rule file.
 76 | ---
 77 | 
 78 | ### Tools used
 79 | 
 80 | None - This rule performs static analysis based on provided component files and styleguide requirements.
 81 | 
 82 | ### Flow
 83 | 
 84 | > You don't need to manually perform any of the listed actions except providing the initial parameters.
 85 | 
 86 | 1. **Input Validation**: Verify component files and styleguide are provided
 87 | 2. **File Structure Check**: Ensure TypeScript, template, and style files are available
 88 | 3. **Multi-Category Analysis**: Evaluate component against five key dimensions
 89 | 4. **Scoring Assignment**: Assign numerical scores (1-10) for each category
 90 | 5. **Observation Collection**: Identify 3-5 concrete issues per category
 91 | 6. **Narrative Generation**: Create overall component state summary
 92 | 7. **Checklist Creation**: Generate actionable improvement items
 93 | 8. **Approval Request**: Present checklist for user review and approval
 94 | 
 95 | The rule enforces structured output with `<component_analysis>`, `<scoring>`, and `<refactoring_checklist>` tags, ensuring comprehensive coverage and clear next steps.
 96 | 
 97 | ### Preferred model
 98 | 
 99 | Claude-4-Sonnet
100 | 
101 | ## 02-refactor-component.mdc
102 | 
103 | ### Goal
104 | 
105 | Execute the approved refactoring checklist by implementing code changes, tracking progress, and maintaining component contracts for validation. This rule systematically processes each checklist item and documents all modifications made to the component.
106 | 
107 | ### Process
108 | 
109 | To start this process, drag file `02-refactor-component.mdc` to the cursor chat and provide:
110 | 
111 | ```
112 | component_path=path/to/component.ts
113 | checklist_content=[the approved checklist from step 1]
114 | 
115 | @02-refactor-component.mdc
116 | ```
117 | 
118 | The rule implements a systematic refactoring execution process:
119 | 
120 | **Step 1: Pre-Refactor Contract Generation**
121 | - Creates baseline component contract capturing current state
122 | - Documents component's public API, DOM structure, and styles
123 | - Establishes reference point for later validation
124 | - Stops process if contract generation fails
125 | 
126 | **Step 2: Checklist Processing**
127 | - Iterates through each unchecked item in the approved checklist
128 | - Implements necessary code changes using standard editing tools
129 | - Marks completed items with explanatory notes
130 | - Handles ambiguous items by requesting user clarification
131 | 
132 | **Step 3: Progress Documentation**
133 | - Updates checklist with completion status and change descriptions
134 | - Saves updated checklist to `.cursor/tmp/component-refactor-checklist-{{COMPONENT_PATH}}.md`
135 | - Maintains audit trail of all modifications
136 | 
137 | **Step 4: Summary Generation**
138 | - Creates comprehensive summary of completed changes
139 | - Documents what was modified and why
140 | - Provides updated checklist in markdown format
141 | 
142 | ---
143 | **🚦 Quality Gate 2**
144 | 
145 | At this point, all checklist items have been processed. You must review the refactoring results.
146 | 
147 | **Required Actions:**
148 | - Review the refactor summary and completed changes
149 | - Verify all checklist items were addressed appropriately
150 | - Resolve any ambiguities or questions
151 | 
152 | **Next Step:** After approving the refactoring results, attach the validation rule file.
153 | ---
154 | 
155 | ### Tools used
156 | 
157 | - `build_component_contract` - Creates component contracts for safe refactoring
158 |   - Parameters: `saveLocation`, `typescriptFile` (required), `templateFile` (optional), `styleFile` (optional), `dsComponentName` (optional, set to "AUTO")
159 |   - Returns: contract path with component's public API, DOM structure, and styles
160 |   - Purpose: Establish baseline for validation comparison
161 |   - Note: Template and style files are optional for components with inline templates/styles
162 | 
163 | - `get-ds-component-data` - Retrieves Design System component information when needed
164 |   - Parameters: `componentName`, `sections` (optional) - Array of sections to include: "implementation", "documentation", "stories", "all"
165 |   - Returns: Selective component data based on refactoring needs
166 |   - Purpose: Access DS component documentation and examples for proper implementation patterns
167 | 
168 | ### Flow
169 | 
170 | > You don't need to manually perform any of the listed actions except providing the initial parameters.
171 | 
172 | 1. **Contract Generation**: Create pre-refactor component contract
173 | 2. **Error Handling**: Verify contract creation succeeded
174 | 3. **Checklist Iteration**: Process each unchecked item systematically
175 | 4. **Code Implementation**: Execute necessary changes for each item
176 | 5. **Progress Tracking**: Mark items complete with explanatory notes
177 | 6. **Ambiguity Resolution**: Request clarification for unclear items
178 | 7. **Checklist Persistence**: Save updated checklist to temporary file
179 | 8. **Summary Creation**: Generate comprehensive refactoring summary
180 | 9. **Completion Confirmation**: Request user approval to proceed to validation
181 | 
182 | The rule enforces structured output with `<refactor_summary>` and `<checklist_updated>` tags, ensuring complete documentation of all changes and clear transition to validation.
183 | 
184 | ### Preferred model
185 | 
186 | Claude-4-Sonnet
187 | 
188 | ## 03-validate-component.mdc
189 | 
190 | ### Goal
191 | 
192 | Analyze the refactored component by comparing before and after contracts, re-evaluating quality scores, and providing comprehensive validation assessment. This rule ensures refactoring improvements are measurable and identifies any remaining issues.
193 | 
194 | ### Process
195 | 
196 | To start this process, drag file `03-validate-component.mdc` to the cursor chat and provide:
197 | 
198 | ```
199 | component_path=path/to/component.ts
200 | baseline_contract_path=path/to/baseline/contract.json
201 | 
202 | @03-validate-component.mdc
203 | ```
204 | 
205 | The rule implements a comprehensive validation process:
206 | 
207 | **Step 1: Post-Refactor Contract Generation**
208 | - Creates new component contract capturing refactored state
209 | - Documents updated component API, DOM structure, and styles
210 | - Establishes comparison point against baseline contract
211 | 
212 | **Step 2: Contract Comparison**
213 | - Performs detailed diff analysis between baseline and updated contracts
214 | - Identifies specific changes in component structure and behavior
215 | - Analyzes impact of modifications on component functionality
216 | 
217 | **Step 3: Quality Re-Assessment**
218 | - Re-evaluates component against the same five categories from initial review:
219 |   - **Accessibility**: Impact of changes on accessibility features
220 |   - **Performance**: Improvements or regressions in performance metrics
221 |   - **Scalability**: Changes affecting component scalability
222 |   - **Maintainability**: Impact on code maintainability and clarity
223 |   - **Best Practices**: Adherence to modern Angular best practices
224 | 
225 | **Step 4: Score Calculation**
226 | - Assigns new scores (1-10) for each category
227 | - Calculates deltas showing improvement or regression
228 | - Provides objective measurement of refactoring success
229 | 
230 | **Step 5: Validation Assessment**
231 | - Determines overall refactoring success or identifies remaining issues
232 | - Highlights any risks or necessary follow-ups
233 | - Provides final judgment on component quality
234 | 
235 | ### Tools used
236 | 
237 | - `build_component_contract` - Creates post-refactor component contract
238 |   - Parameters: `saveLocation`, `typescriptFile` (required), `templateFile` (optional), `styleFile` (optional), `dsComponentName` (optional)
239 |   - Returns: updated contract path with refactored component state
240 |   - Purpose: Capture final component state for comparison
241 |   - Note: Template and style files are optional for components with inline templates/styles
242 | 
243 | - `diff_component_contract` - Compares baseline and updated contracts
244 |   - Parameters: `saveLocation`, `contractBeforePath`, `contractAfterPath`, `dsComponentName`
245 |   - Returns: detailed diff analysis showing specific changes
246 |   - Purpose: Identify and analyze all modifications made during refactoring
247 | 
248 | ### Flow
249 | 
250 | > You don't need to manually perform any of the listed actions except providing the initial parameters.
251 | 
252 | 1. **Post-Contract Generation**: Create contract for refactored component
253 | 2. **Error Handling**: Verify contract creation succeeded
254 | 3. **Contract Comparison**: Generate diff analysis between baseline and updated contracts
255 | 4. **Change Analysis**: Analyze diff results for impact assessment
256 | 5. **Quality Re-Evaluation**: Re-score component across five categories
257 | 6. **Delta Calculation**: Compute improvement or regression metrics
258 | 7. **Impact Assessment**: Evaluate overall refactoring effectiveness
259 | 8. **Validation Judgment**: Determine success status and identify remaining issues
260 | 9. **Final Report**: Generate comprehensive validation assessment
261 | 
262 | The rule enforces structured output with `<diff_summary>`, `<new_scoring>`, and `<validation_assessment>` tags, ensuring objective measurement of refactoring success and clear identification of any remaining concerns.
263 | 
264 | ### Preferred model
265 | 
266 | Claude-4-Sonnet
267 | 
268 | ## Integration with Angular 20 Best Practices
269 | 
270 | The component refactoring flow specifically targets modern Angular development patterns as outlined in the `angular-20.md` reference document. Key focus areas include:
271 | 
272 | ### TypeScript Modernization
273 | - **Strict Type Checking**: Ensures proper type safety throughout component
274 | - **Type Inference**: Reduces verbosity while maintaining type safety
275 | - **Avoiding `any`**: Promotes use of `unknown` and proper type definitions
276 | 
277 | ### Angular Modern Patterns
278 | - **Standalone Components**: Migrates from NgModule-based to standalone architecture
279 | - **Signals for State Management**: Adopts reactive state management with Angular Signals
280 | - **New Input/Output Syntax**: Replaces decorators with `input()` and `output()` functions
281 | - **Computed Properties**: Implements `computed()` for derived state
282 | 
283 | ### Template Modernization
284 | - **Control Flow Syntax**: Migrates from structural directives to `@if`, `@for`, `@switch`
285 | - **Native Class/Style Bindings**: Replaces `ngClass`/`ngStyle` with native bindings
286 | - **OnPush Change Detection**: Implements performance optimization strategies
287 | 
288 | ### Service and Dependency Injection
289 | - **Inject Function**: Adopts modern `inject()` function over constructor injection
290 | - **Providable Services**: Ensures proper service registration and tree-shaking
291 | 
292 | This comprehensive approach ensures components are not only improved but also aligned with the latest Angular best practices and performance recommendations. 
```

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

```typescript
  1 | import * as ts from 'typescript';
  2 | import {
  3 |   MethodSignature,
  4 |   ParameterInfo,
  5 |   ImportInfo,
  6 | } from '../../shared/models/types.js';
  7 | import {
  8 |   DecoratorInputMeta,
  9 |   DecoratorOutputMeta,
 10 |   SignalInputMeta,
 11 |   SignalOutputMeta,
 12 |   ExtractedInputsOutputs,
 13 | } from '../models/types.js';
 14 | import { ParsedComponent } from '@push-based/angular-ast-utils';
 15 | 
 16 | /**
 17 |  * Angular lifecycle hooks that we can detect
 18 |  */
 19 | const LIFECYCLE_HOOKS = new Set<string>([
 20 |   'OnInit',
 21 |   'OnDestroy',
 22 |   'OnChanges',
 23 |   'DoCheck',
 24 |   'AfterContentInit',
 25 |   'AfterContentChecked',
 26 |   'AfterViewInit',
 27 |   'AfterViewChecked',
 28 | ]);
 29 | 
 30 | /**
 31 |  * Utility: check whether a node has a given modifier
 32 |  */
 33 | const hasModifier = (
 34 |   node: { modifiers?: ts.NodeArray<ts.ModifierLike> },
 35 |   kind: ts.SyntaxKind,
 36 | ): boolean => node.modifiers?.some((m) => m.kind === kind) ?? false;
 37 | 
 38 | /**
 39 |  * Extract public methods from a TypeScript class declaration
 40 |  */
 41 | export function extractPublicMethods(
 42 |   classNode: ts.ClassDeclaration,
 43 |   sourceFile: ts.SourceFile,
 44 | ): Record<string, MethodSignature> {
 45 |   const methods: Record<string, MethodSignature> = {};
 46 | 
 47 |   for (const member of classNode.members) {
 48 |     if (!ts.isMethodDeclaration(member) || !ts.isIdentifier(member.name)) {
 49 |       continue;
 50 |     }
 51 | 
 52 |     const methodName = member.name.text;
 53 | 
 54 |     if (
 55 |       methodName.startsWith('ng') &&
 56 |       LIFECYCLE_HOOKS.has(methodName.slice(2))
 57 |     ) {
 58 |       continue;
 59 |     }
 60 | 
 61 |     if (
 62 |       hasModifier(member, ts.SyntaxKind.PrivateKeyword) ||
 63 |       hasModifier(member, ts.SyntaxKind.ProtectedKeyword)
 64 |     ) {
 65 |       continue;
 66 |     }
 67 | 
 68 |     methods[methodName] = {
 69 |       name: methodName,
 70 |       parameters: extractParameters(member.parameters, sourceFile),
 71 |       returnType: extractReturnType(member, sourceFile),
 72 |       isPublic: true,
 73 |       isStatic: hasModifier(member, ts.SyntaxKind.StaticKeyword),
 74 |       isAsync: hasModifier(member, ts.SyntaxKind.AsyncKeyword),
 75 |     };
 76 |   }
 77 | 
 78 |   return methods;
 79 | }
 80 | 
 81 | /**
 82 |  * Extract parameter information from method parameters
 83 |  */
 84 | function extractParameters(
 85 |   parameters: ts.NodeArray<ts.ParameterDeclaration>,
 86 |   sourceFile: ts.SourceFile,
 87 | ): ParameterInfo[] {
 88 |   return parameters.map((param) => ({
 89 |     name: ts.isIdentifier(param.name) ? param.name.text : 'unknown',
 90 |     type: param.type?.getText(sourceFile) ?? 'any',
 91 |     optional: !!param.questionToken,
 92 |     defaultValue: param.initializer?.getText(sourceFile),
 93 |   }));
 94 | }
 95 | 
 96 | /**
 97 |  * Extract return type from method declaration
 98 |  */
 99 | function extractReturnType(
100 |   method: ts.MethodDeclaration,
101 |   sourceFile: ts.SourceFile,
102 | ): string {
103 |   return (
104 |     method.type?.getText(sourceFile) ??
105 |     (hasModifier(method, ts.SyntaxKind.AsyncKeyword) ? 'Promise<any>' : 'any')
106 |   );
107 | }
108 | 
109 | /**
110 |  * Extract implemented Angular lifecycle hooks
111 |  */
112 | export function extractLifecycleHooks(
113 |   classNode: ts.ClassDeclaration,
114 | ): string[] {
115 |   const implementedHooks = new Set<string>();
116 | 
117 |   if (classNode.heritageClauses) {
118 |     for (const heritage of classNode.heritageClauses) {
119 |       if (heritage.token === ts.SyntaxKind.ImplementsKeyword) {
120 |         for (const type of heritage.types) {
121 |           if (ts.isIdentifier(type.expression)) {
122 |             const interfaceName = type.expression.text;
123 |             if (LIFECYCLE_HOOKS.has(interfaceName)) {
124 |               implementedHooks.add(interfaceName);
125 |             }
126 |           }
127 |         }
128 |       }
129 |     }
130 |   }
131 | 
132 |   for (const member of classNode.members) {
133 |     if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
134 |       const methodName = member.name.text;
135 |       if (
136 |         methodName.startsWith('ng') &&
137 |         LIFECYCLE_HOOKS.has(methodName.slice(2))
138 |       ) {
139 |         implementedHooks.add(methodName.slice(2));
140 |       }
141 |     }
142 |   }
143 | 
144 |   return Array.from(implementedHooks);
145 | }
146 | 
147 | /**
148 |  * Extract TypeScript class declaration from parsed component
149 |  * This function finds the class node from the component's source file
150 |  */
151 | export function extractClassDeclaration(
152 |   parsedComponent: ParsedComponent,
153 | ): ts.ClassDeclaration | null {
154 |   if (!parsedComponent.fileName) {
155 |     return null;
156 |   }
157 | 
158 |   try {
159 |     const program = ts.createProgram([parsedComponent.fileName], {
160 |       target: ts.ScriptTarget.Latest,
161 |       module: ts.ModuleKind.ESNext,
162 |       experimentalDecorators: true,
163 |     });
164 | 
165 |     const sourceFile = program.getSourceFile(parsedComponent.fileName);
166 |     if (!sourceFile) {
167 |       return null;
168 |     }
169 | 
170 |     const classNode = findClassDeclaration(
171 |       sourceFile,
172 |       parsedComponent.className,
173 |     );
174 |     return classNode;
175 |   } catch (ctx) {
176 |     console.warn(
177 |       `Failed to extract class declaration for ${parsedComponent.className}:`,
178 |       ctx,
179 |     );
180 |     return null;
181 |   }
182 | }
183 | 
184 | /**
185 |  * Find class declaration by name in source file
186 |  */
187 | function findClassDeclaration(
188 |   sourceFile: ts.SourceFile,
189 |   className: string,
190 | ): ts.ClassDeclaration | null {
191 |   let foundClass: ts.ClassDeclaration | null = null;
192 | 
193 |   function visit(node: ts.Node) {
194 |     if (
195 |       ts.isClassDeclaration(node) &&
196 |       node.name &&
197 |       node.name.text === className
198 |     ) {
199 |       foundClass = node;
200 |       return;
201 |     }
202 |     ts.forEachChild(node, visit);
203 |   }
204 | 
205 |   visit(sourceFile);
206 |   return foundClass;
207 | }
208 | 
209 | /**
210 |  * Extract import statements from source file
211 |  */
212 | export function extractImports(sourceFile: ts.SourceFile): ImportInfo[] {
213 |   const imports: ImportInfo[] = [];
214 | 
215 |   function visit(node: ts.Node) {
216 |     if (ts.isImportDeclaration(node) && node.moduleSpecifier) {
217 |       const moduleSpecifier = node.moduleSpecifier;
218 |       if (ts.isStringLiteral(moduleSpecifier)) {
219 |         if (node.importClause) {
220 |           if (node.importClause.name) {
221 |             imports.push({
222 |               name: node.importClause.name.text,
223 |               path: moduleSpecifier.text,
224 |             });
225 |           }
226 | 
227 |           if (node.importClause.namedBindings) {
228 |             if (ts.isNamespaceImport(node.importClause.namedBindings)) {
229 |               imports.push({
230 |                 name: node.importClause.namedBindings.name.text,
231 |                 path: moduleSpecifier.text,
232 |               });
233 |             } else if (ts.isNamedImports(node.importClause.namedBindings)) {
234 |               for (const element of node.importClause.namedBindings.elements) {
235 |                 imports.push({
236 |                   name: element.name.text,
237 |                   path: moduleSpecifier.text,
238 |                 });
239 |               }
240 |             }
241 |           }
242 |         }
243 |       }
244 |     }
245 |     ts.forEachChild(node, visit);
246 |   }
247 | 
248 |   visit(sourceFile);
249 |   return imports;
250 | }
251 | 
252 | // Helper: determine if class member is a public property with identifier name
253 | function isPublicProp(
254 |   member: ts.ClassElement,
255 | ): member is ts.PropertyDeclaration & { name: ts.Identifier } {
256 |   return (
257 |     ts.isPropertyDeclaration(member) &&
258 |     ts.isIdentifier(member.name) &&
259 |     !hasModifier(member, ts.SyntaxKind.PrivateKeyword) &&
260 |     !hasModifier(member, ts.SyntaxKind.ProtectedKeyword)
261 |   );
262 | }
263 | 
264 | export function extractInputsAndOutputs(
265 |   classNode: ts.ClassDeclaration,
266 |   sourceFile: ts.SourceFile,
267 | ): ExtractedInputsOutputs {
268 |   const inputs: Record<string, DecoratorInputMeta | SignalInputMeta> = {};
269 |   const outputs: Record<string, DecoratorOutputMeta | SignalOutputMeta> = {};
270 | 
271 |   for (const member of classNode.members) {
272 |     if (!isPublicProp(member)) continue;
273 | 
274 |     const name = member.name.text;
275 |     const { isInput, isOutput, type, required, alias } =
276 |       extractDecoratorInputsOutputs(member, sourceFile);
277 | 
278 |     if (isInput) inputs[name] = { name, type, required, alias } as any;
279 |     if (isOutput) outputs[name] = { name, type, alias } as any;
280 | 
281 |     const init = member.initializer;
282 |     if (
283 |       !init ||
284 |       !ts.isCallExpression(init) ||
285 |       !ts.isIdentifier(init.expression)
286 |     ) {
287 |       continue;
288 |     }
289 | 
290 |     switch (init.expression.text) {
291 |       case 'input':
292 |         inputs[name] = {
293 |           name,
294 |           ...(extractSignalInputMetadata(init, member, sourceFile) as any),
295 |         } as any;
296 |         break;
297 |       case 'output':
298 |         outputs[name] = {
299 |           name,
300 |           ...(extractSignalOutputMetadata(init, member, sourceFile) as any),
301 |         } as any;
302 |         break;
303 |     }
304 |   }
305 | 
306 |   return { inputs, outputs };
307 | }
308 | 
309 | function extractDecoratorInputsOutputs(
310 |   member: ts.PropertyDeclaration,
311 |   sourceFile: ts.SourceFile,
312 | ): {
313 |   isInput: boolean;
314 |   isOutput: boolean;
315 |   type?: string;
316 |   required?: boolean;
317 |   alias?: string;
318 | } {
319 |   let isInput = false,
320 |     isOutput = false,
321 |     alias: string | undefined,
322 |     required = false;
323 | 
324 |   member.modifiers?.forEach((mod) => {
325 |     if (!ts.isDecorator(mod)) return;
326 | 
327 |     const kind = getDecoratorName(mod); // 'Input' | 'Output' | null
328 |     if (!kind) return;
329 | 
330 |     const args = getDecoratorArguments(mod);
331 |     const first = args[0];
332 | 
333 |     if (first && ts.isStringLiteral(first)) {
334 |       alias = first.text;
335 |     }
336 | 
337 |     if (kind === 'Input') {
338 |       isInput = true;
339 |       if (first && ts.isObjectLiteralExpression(first)) {
340 |         first.properties.forEach((p) => {
341 |           if (!ts.isPropertyAssignment(p) || !ts.isIdentifier(p.name)) return;
342 |           if (p.name.text === 'alias' && ts.isStringLiteral(p.initializer)) {
343 |             alias = p.initializer.text;
344 |           }
345 |           if (p.name.text === 'required') {
346 |             required = p.initializer.kind === ts.SyntaxKind.TrueKeyword;
347 |           }
348 |         });
349 |       }
350 |     } else if (kind === 'Output') {
351 |       isOutput = true;
352 |     }
353 |   });
354 | 
355 |   const type = extractPropertyType(member, sourceFile, isOutput);
356 | 
357 |   return { isInput, isOutput, type, required, alias };
358 | }
359 | 
360 | function getDecoratorName(decorator: ts.Decorator): string | null {
361 |   if (ts.isCallExpression(decorator.expression)) {
362 |     if (ts.isIdentifier(decorator.expression.expression)) {
363 |       return decorator.expression.expression.text;
364 |     }
365 |   } else if (ts.isIdentifier(decorator.expression)) {
366 |     return decorator.expression.text;
367 |   }
368 |   return null;
369 | }
370 | 
371 | function getDecoratorArguments(decorator: ts.Decorator): ts.Expression[] {
372 |   if (ts.isCallExpression(decorator.expression)) {
373 |     return Array.from(decorator.expression.arguments);
374 |   }
375 |   return [];
376 | }
377 | 
378 | function extractPropertyType(
379 |   member: ts.PropertyDeclaration,
380 |   sourceFile: ts.SourceFile,
381 |   isOutput = false,
382 | ): string {
383 |   if (member.type) {
384 |     const typeText = member.type.getText(sourceFile);
385 |     return typeText;
386 |   }
387 | 
388 |   if (member.initializer) {
389 |     if (ts.isNewExpression(member.initializer)) {
390 |       const expression = member.initializer.expression;
391 |       if (ts.isIdentifier(expression)) {
392 |         if (expression.text === 'EventEmitter') {
393 |           if (
394 |             member.initializer.typeArguments &&
395 |             member.initializer.typeArguments.length > 0
396 |           ) {
397 |             return `EventEmitter<${member.initializer.typeArguments[0].getText(sourceFile)}>`;
398 |           }
399 |           return 'EventEmitter<any>';
400 |         }
401 |       }
402 |     }
403 |   }
404 | 
405 |   if (isOutput) {
406 |     return 'EventEmitter<any>';
407 |   }
408 |   return 'any';
409 | }
410 | 
411 | function extractSignalInputMetadata(
412 |   callExpression: ts.CallExpression,
413 |   propertyDeclaration: ts.PropertyDeclaration,
414 |   sourceFile: ts.SourceFile,
415 | ): Omit<SignalInputMeta, 'name'> {
416 |   const meta: Omit<SignalInputMeta, 'name'> = {};
417 | 
418 |   meta.type = extractInputType(callExpression, propertyDeclaration, sourceFile);
419 | 
420 |   if (callExpression.arguments.length > 0) {
421 |     const firstArg = callExpression.arguments[0];
422 |     meta.defaultValue = firstArg.getText(sourceFile);
423 |     meta.required = false;
424 |   } else {
425 |     meta.required = true;
426 |   }
427 | 
428 |   if (callExpression.arguments.length > 1) {
429 |     const optionsArg = callExpression.arguments[1];
430 |     if (ts.isObjectLiteralExpression(optionsArg)) {
431 |       for (const property of optionsArg.properties) {
432 |         if (
433 |           ts.isPropertyAssignment(property) &&
434 |           ts.isIdentifier(property.name)
435 |         ) {
436 |           const propName = property.name.text;
437 |           if (propName === 'transform') {
438 |             meta.transform = property.initializer.getText(sourceFile);
439 |           }
440 |         }
441 |       }
442 |     }
443 |   }
444 | 
445 |   return meta;
446 | }
447 | 
448 | function extractSignalOutputMetadata(
449 |   callExpression: ts.CallExpression,
450 |   propertyDeclaration: ts.PropertyDeclaration,
451 |   sourceFile: ts.SourceFile,
452 | ): Omit<SignalOutputMeta, 'name'> {
453 |   const meta: Omit<SignalOutputMeta, 'name'> = {};
454 | 
455 |   meta.type = extractOutputType(
456 |     callExpression,
457 |     propertyDeclaration,
458 |     sourceFile,
459 |   );
460 | 
461 |   return meta;
462 | }
463 | 
464 | function extractInputType(
465 |   callExpression: ts.CallExpression,
466 |   propertyDeclaration: ts.PropertyDeclaration,
467 |   sourceFile: ts.SourceFile,
468 | ): string {
469 |   if (callExpression.typeArguments && callExpression.typeArguments.length > 0) {
470 |     return callExpression.typeArguments[0].getText(sourceFile);
471 |   }
472 | 
473 |   if (propertyDeclaration.type) {
474 |     return extractTypeFromInputSignal(propertyDeclaration.type, sourceFile);
475 |   }
476 | 
477 |   return 'any';
478 | }
479 | 
480 | function extractOutputType(
481 |   callExpression: ts.CallExpression,
482 |   propertyDeclaration: ts.PropertyDeclaration,
483 |   sourceFile: ts.SourceFile,
484 | ): string {
485 |   if (callExpression.typeArguments && callExpression.typeArguments.length > 0) {
486 |     return `EventEmitter<${callExpression.typeArguments[0].getText(sourceFile)}>`;
487 |   }
488 | 
489 |   if (propertyDeclaration.type) {
490 |     return extractTypeFromOutputEmitter(propertyDeclaration.type, sourceFile);
491 |   }
492 | 
493 |   return 'EventEmitter<any>';
494 | }
495 | 
496 | function extractTypeFromInputSignal(
497 |   typeNode: ts.TypeNode,
498 |   sourceFile: ts.SourceFile,
499 | ): string {
500 |   if (
501 |     ts.isTypeReferenceNode(typeNode) &&
502 |     typeNode.typeArguments &&
503 |     typeNode.typeArguments.length > 0
504 |   ) {
505 |     return typeNode.typeArguments[0].getText(sourceFile);
506 |   }
507 |   return typeNode.getText(sourceFile);
508 | }
509 | 
510 | function extractTypeFromOutputEmitter(
511 |   typeNode: ts.TypeNode,
512 |   sourceFile: ts.SourceFile,
513 | ): string {
514 |   if (
515 |     ts.isTypeReferenceNode(typeNode) &&
516 |     typeNode.typeArguments &&
517 |     typeNode.typeArguments.length > 0
518 |   ) {
519 |     return `EventEmitter<${typeNode.typeArguments[0].getText(sourceFile)}>`;
520 |   }
521 |   return `EventEmitter<${typeNode.getText(sourceFile)}>`;
522 | }
523 | 
524 | export const extractSignalInputsAndOutputs = extractInputsAndOutputs;
525 | 
```

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

```typescript
  1 | import { generateStatusBadges } from '@design-system/shared-storybook-utils';
  2 | import {
  3 |   DemoChevronComponent,
  4 |   DemoCloseIconComponent,
  5 |   DemoIconComponent,
  6 | } from '@design-system/storybook-demo-cmp-lib';
  7 | import { DsBadge } from '@frontend/ui/badge';
  8 | import { DsButton } from '@frontend/ui/button';
  9 | import { DsButtonIcon } from '@frontend/ui/button-icon';
 10 | import {
 11 |   DsModal,
 12 |   DsModalContent,
 13 |   DsModalHeader,
 14 |   DsModalHeaderDrag,
 15 |   DsModalHeaderVariant,
 16 | } from '@frontend/ui/modal';
 17 | import { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';
 18 | 
 19 | import { DemoCdkModalContainer } from './demo-cdk-dialog-cmp.component';
 20 | import { DemoModalContainer } from './demo-modal-cmp.component';
 21 | 
 22 | type DsModalStoryType = DsModal & { headerVariant: DsModalHeaderVariant };
 23 | 
 24 | const meta: Meta<DsModalStoryType> = {
 25 |   title: 'Components/Modal',
 26 |   component: DsModal,
 27 |   parameters: {
 28 |     status: generateStatusBadges('UX-2414', ['integration ready']),
 29 |   },
 30 |   excludeStories: /.*Data$/,
 31 |   argTypes: {
 32 |     headerVariant: {
 33 |       options: [
 34 |         'surface-lowest',
 35 |         'surface-low',
 36 |         'surface',
 37 |         'surface-high',
 38 |         'nav-bg',
 39 |       ],
 40 |       table: { defaultValue: { summary: 'surface' }, category: 'Styling' },
 41 |       control: { type: 'select' },
 42 |       description: 'Surface type',
 43 |     },
 44 |     variant: {
 45 |       options: ['surface-lowest', 'surface-low', 'surface'],
 46 |       table: { defaultValue: { summary: 'surface' }, category: 'Styling' },
 47 |       control: { type: 'select' },
 48 |       description: 'Surface type',
 49 |     },
 50 |     inverse: {
 51 |       type: 'boolean',
 52 |       table: { defaultValue: { summary: 'false' }, category: 'Styling' },
 53 |       control: { type: 'boolean' },
 54 |       description: 'The inverse state of the Modal',
 55 |     },
 56 |     bottomSheet: {
 57 |       type: 'boolean',
 58 |       table: { defaultValue: { summary: 'false' }, category: 'Styling' },
 59 |       control: { type: 'boolean' },
 60 |       description: 'The dialog should open from bottom',
 61 |     },
 62 |   },
 63 |   args: {
 64 |     headerVariant: 'surface',
 65 |     inverse: false,
 66 |     bottomSheet: true,
 67 |     variant: 'surface',
 68 |   },
 69 |   decorators: [
 70 |     moduleMetadata({
 71 |       imports: [
 72 |         DsModal,
 73 |         DemoIconComponent,
 74 |         DemoCloseIconComponent,
 75 |         DsButton,
 76 |         DsButtonIcon,
 77 |         DemoChevronComponent,
 78 |         DsBadge,
 79 |         DsModalHeader,
 80 |         DsModalContent,
 81 |         DsModalHeaderDrag,
 82 |         DemoModalContainer,
 83 |         DemoCdkModalContainer,
 84 |       ],
 85 |     }),
 86 |   ],
 87 | };
 88 | 
 89 | export default meta;
 90 | type Story = StoryObj<DsModalStoryType>;
 91 | 
 92 | export const Default: Story = {
 93 |   render: () => ({
 94 |     template: `<ds-modal style="width: 250px; min-height: 120px"></ds-modal>`,
 95 |   }),
 96 | };
 97 | 
 98 | export const WithMatDialog: Story = {
 99 |   render: (modal) => ({
100 |     template: `
101 |             <div>
102 |                 <ds-demo-dialog-container headerVariant="${modal.headerVariant}" inverse="${modal.inverse}" variant="${modal.variant}" bottomSheetInput="${modal.bottomSheet}"/>
103 |             </div>
104 |         `,
105 |   }),
106 | };
107 | 
108 | export const WithCdkDialog: Story = {
109 |   render: (modal) => ({
110 |     template: `
111 |             <div>
112 |                 <ds-demo-cdk-dialog-container headerVariant="${modal.headerVariant}" variant="${modal.variant}" inverse="${modal.inverse}" bottomSheetInput="${modal.bottomSheet}" />
113 |             </div>
114 |         `,
115 |   }),
116 | };
117 | 
118 | export const ModalWithContentOnly: Story = {
119 |   argTypes: {
120 |     bottomSheet: {
121 |       table: { disable: true },
122 |     },
123 |   },
124 |   render: (args) => ({
125 |     template: `
126 |             <ds-modal variant="${args.variant}" inverse="${args.inverse}" style="width: 250px;">
127 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
128 |             </ds-modal>
129 |         `,
130 |   }),
131 | };
132 | 
133 | export const WithTitleAndClose: Story = {
134 |   argTypes: {
135 |     bottomSheet: {
136 |       table: { disable: true },
137 |     },
138 |   },
139 |   render: (args) => ({
140 |     template: `
141 |             <ds-modal inverse="${args.inverse}" variant="${args.variant}" >
142 |                 <ds-modal-header variant="${args.headerVariant}">
143 |                     <div slot="start">
144 |                         <div slot="title">Hello world</div>
145 |                     </div>
146 |                     <button slot="end" ds-button-icon size="small" variant="flat" kind="utility">
147 |                         <ds-demo-close-icon />
148 |                     </button>
149 |                 </ds-modal-header>
150 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
151 |             </ds-modal>
152 |         `,
153 |   }),
154 | };
155 | 
156 | export const WithDragger: Story = {
157 |   argTypes: {
158 |     bottomSheet: {
159 |       table: { disable: true },
160 |     },
161 |   },
162 |   render: (args) => ({
163 |     template: `
164 |             <ds-modal variant="${args.variant}" inverse="${args.inverse}" >
165 |                 <ds-modal-header variant="${args.headerVariant}">
166 |                    <ds-modal-header-drag />
167 |                 </ds-modal-header>
168 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
169 |             </ds-modal>
170 |         `,
171 |   }),
172 | };
173 | 
174 | export const BolderSubtitleThanTitle: Story = {
175 |   argTypes: {
176 |     bottomSheet: {
177 |       table: { disable: true },
178 |     },
179 |   },
180 |   render: (args) => ({
181 |     template: `
182 |             <ds-modal variant="${args.variant}" inverse="${args.inverse}" >
183 |                 <ds-modal-header variant="${args.headerVariant}">
184 |                     <button slot="start" ds-button variant="outline" size="medium">Cancel</button>
185 |                     <div slot="center">
186 |                         <div slot="title">Title</div>
187 |                         <div slot="subtitle">Subtitle</div>
188 |                     </div>
189 |                     <button slot="end" ds-button variant="filled" size="medium">
190 |                         <ds-demo-icon slot="start" />
191 |                         Agree
192 |                     </button>
193 |                 </ds-modal-header>
194 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
195 |             </ds-modal>
196 |         `,
197 |   }),
198 | };
199 | 
200 | export const ActionsAndCenteredTitle: Story = {
201 |   argTypes: {
202 |     bottomSheet: {
203 |       table: { disable: true },
204 |     },
205 |   },
206 |   render: (args) => ({
207 |     template: `
208 |             <ds-modal variant="${args.variant}" inverse="${args.inverse}" >
209 |                 <ds-modal-header variant="${args.headerVariant}">
210 |                     <button slot="start" ds-button variant="outline" size="medium">Cancel</button>
211 |                     <div slot="center">
212 |                         <div slot="title">Hello world</div>
213 |                         <div slot="subtitle">From DS team</div>
214 |                     </div>
215 |                     <button slot="end" ds-button variant="filled" size="medium">
216 |                         <ds-demo-icon slot="start" />
217 |                         Agree
218 |                     </button>
219 |                 </ds-modal-header>
220 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
221 |             </ds-modal>
222 |         `,
223 |   }),
224 | };
225 | 
226 | export const CloseTitleLabelAction: Story = {
227 |   argTypes: {
228 |     bottomSheet: {
229 |       table: { disable: true },
230 |     },
231 |   },
232 |   render: (args) => ({
233 |     template: `
234 |             <ds-modal variant="${args.variant}" inverse="${args.inverse}" >
235 |                 <ds-modal-header variant="${args.headerVariant}">
236 |                     <ng-container slot="start" >
237 |                       <button ds-button-icon variant="outline" size="medium" kind="secondary">
238 |                         <ds-demo-close-icon />                        
239 |                       </button>
240 |                       <div slot="title">
241 |                         Hello world
242 |                         <ds-badge variant="blue">Label</ds-badge>
243 |                       </div>
244 |                     </ng-container>
245 |                     <ng-container slot="end">
246 |                         <ds-demo-icon slot="start" />
247 |                         <button slot="end" ds-button variant="outline" size="medium">
248 |                           Action
249 |                         </button>
250 |                     </ng-container>
251 |                 </ds-modal-header>
252 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
253 |             </ds-modal>
254 |         `,
255 |   }),
256 | };
257 | 
258 | export const BackBtnTitleLabelAction: Story = {
259 |   argTypes: {
260 |     bottomSheet: {
261 |       table: { disable: true },
262 |     },
263 |   },
264 |   render: (args) => ({
265 |     template: `
266 |             <ds-modal variant="${args.variant}" inverse="${args.inverse}" >
267 |                 <ds-modal-header variant="${args.headerVariant}">
268 |                     <ng-container slot="start">
269 |                       <button ds-button-icon variant="outline" size="medium" kind="secondary">
270 |                         <ds-demo-chevron rotation="90" />                        
271 |                       </button>
272 |                       <div style="display: flex; flex-direction: column;">
273 |                         <div slot="title">
274 |                           Hello world
275 |                           <ds-badge variant="blue">Label</ds-badge>
276 |                         </div>
277 |                         <div slot="subtitle">From DS team</div>
278 |                       </div>
279 |                     </ng-container>
280 |                     <ng-container slot="end">
281 |                         <ds-demo-icon slot="start" />
282 |                         <button slot="end" ds-button variant="outline" size="medium">
283 |                           Action
284 |                         </button>
285 |                     </ng-container>
286 |                 </ds-modal-header>
287 |                 <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
288 |             </ds-modal>
289 |         `,
290 |   }),
291 | };
292 | 
293 | export const ModalHeaderTypes: Story = {
294 |   argTypes: {
295 |     headerVariant: {
296 |       table: { disable: true },
297 |     },
298 |     bottomSheet: {
299 |       table: { disable: true },
300 |     },
301 |     variant: {
302 |       table: { disable: true },
303 |     },
304 |   },
305 |   render: (args) => ({
306 |     template: `
307 |             <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px">
308 |                  <div style="display: grid; gap: 10px">
309 |                     <ds-modal inverse="${args.inverse}" >
310 |                         <ds-modal-header variant="surface">
311 |                             <div slot="start">
312 |                                 <div slot="title">Surface</div>
313 |                             </div>
314 |                             <button slot="end" ds-button-icon size="small" variant="flat" kind="utility">
315 |                                 <ds-demo-close-icon />
316 |                             </button>
317 |                         </ds-modal-header>
318 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
319 |                     </ds-modal>
320 |                     <ds-modal inverse="${args.inverse}" >
321 |                         <ds-modal-header variant="surface-lowest">
322 |                             <div slot="start">
323 |                                 <div slot="title">Surface lowest</div>
324 |                             </div>
325 |                             <button slot="end" ds-button-icon size="small" variant="outline" kind="utility">
326 |                                 <ds-demo-close-icon />
327 |                             </button>
328 |                         </ds-modal-header>
329 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
330 |                     </ds-modal>
331 |                     <ds-modal inverse="${args.inverse}" >
332 |                         <ds-modal-header variant="surface-low">
333 |                             <div slot="start">
334 |                                 <div slot="title">Surface low</div>
335 |                             </div>
336 |                             <button slot="end" ds-button-icon size="small" variant="filled" kind="utility">
337 |                                 <ds-demo-close-icon />
338 |                             </button>
339 |                         </ds-modal-header>
340 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
341 |                     </ds-modal>
342 |                     <ds-modal inverse="${args.inverse}" >
343 |                         <ds-modal-header variant="surface-high">
344 |                             <div slot="start">
345 |                                 <div slot="title">Surface High</div>
346 |                             </div>
347 |                             <button slot="end" ds-button-icon size="small" kind="secondary">
348 |                                 <ds-demo-close-icon />
349 |                             </button>
350 |                         </ds-modal-header>
351 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
352 |                     </ds-modal>
353 |                 </div>
354 |                  <div style="display: grid; gap: 10px">
355 |                     <ds-modal inverse="${args.inverse}" >
356 |                         <ds-modal-header variant="surface">
357 |                             <div slot="start">
358 |                                 <div slot="title">Surface</div>
359 |                                 <div slot="subtitle">Header subtitle</div>
360 |                             </div>
361 |                             <div slot="end">
362 |                               <button ds-button-icon size="small" variant="flat" kind="utility">
363 |                                 <ds-demo-close-icon />
364 |                               </button>
365 |                             </div>
366 |                         </ds-modal-header>
367 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
368 |                     </ds-modal>
369 |                     <ds-modal inverse="${args.inverse}" >
370 |                         <ds-modal-header variant="surface-lowest">
371 |                             <div slot="start">
372 |                                 <div slot="title">Surface lowest</div>
373 |                                 <div slot="subtitle">Header subtitle</div>
374 |                             </div>
375 |                             <button slot="end" ds-button-icon size="small" variant="outline" kind="utility">
376 |                                 <ds-demo-close-icon />
377 |                             </button>
378 |                         </ds-modal-header>
379 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
380 |                     </ds-modal>
381 |                     <ds-modal inverse="${args.inverse}" >
382 |                         <ds-modal-header variant="surface-low">
383 |                             <div slot="start">
384 |                                 <div slot="title">Surface low</div>
385 |                                 <div slot="subtitle">Header subtitle</div>
386 |                             </div>
387 |                             <button slot="end" ds-button-icon size="small" kind="utility">
388 |                                 <ds-demo-close-icon />
389 |                             </button>
390 |                         </ds-modal-header>
391 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
392 |                     </ds-modal>
393 |                     <ds-modal inverse="${args.inverse}" >
394 |                         <ds-modal-header variant="surface-high">
395 |                             <div slot="start">
396 |                                 <div slot="title">Surface High</div>
397 |                                 <div slot="subtitle">Header subtitle</div>
398 |                             </div>
399 |                             <button slot="end" ds-button-icon size="small" kind="secondary">
400 |                                 <ds-demo-close-icon />
401 |                             </button>
402 |                         </ds-modal-header>
403 |                         <ds-modal-content> Lorem ipsum dolor sit amet. </ds-modal-content>
404 |                     </ds-modal>
405 |                 </div>
406 |             </div>
407 |         `,
408 |   }),
409 | };
410 | 
```
Page 8/10FirstPrevNextLast