This is page 1 of 10. Use http://codebase.md/push-based/angular-toolkit-mcp?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .aiignore ├── .cursor │ ├── flows │ │ ├── component-refactoring │ │ │ ├── 01-review-component.mdc │ │ │ ├── 02-refactor-component.mdc │ │ │ ├── 03-validate-component.mdc │ │ │ └── angular-20.md │ │ ├── ds-refactoring-flow │ │ │ ├── 01-find-violations.mdc │ │ │ ├── 01b-find-all-violations.mdc │ │ │ ├── 02-plan-refactoring.mdc │ │ │ ├── 02b-plan-refactoring-for-all-violations.mdc │ │ │ ├── 03-fix-violations.mdc │ │ │ ├── 03-non-viable-cases.mdc │ │ │ ├── 04-validate-changes.mdc │ │ │ ├── 05-prepare-report.mdc │ │ │ └── clean-global-styles.mdc │ │ └── README.md │ └── mcp.json.example ├── .github │ └── workflows │ └── ci.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── assets │ ├── entain-logo.png │ └── entain.png ├── CONTRIBUTING.MD ├── docs │ ├── architecture-internal-design.md │ ├── component-refactoring-flow.md │ ├── contracts.md │ ├── ds-refactoring-flow.md │ ├── getting-started.md │ ├── README.md │ ├── tools.md │ └── writing-custom-tools.md ├── eslint.config.mjs ├── jest.config.ts ├── jest.preset.mjs ├── LICENSE ├── nx.json ├── package-lock.json ├── package.json ├── packages │ ├── .gitkeep │ ├── angular-mcp │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── assets │ │ │ │ └── .gitkeep │ │ │ └── main.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ ├── vitest.config.mts │ │ └── webpack.config.cjs │ ├── angular-mcp-server │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── angular-mcp-server.ts │ │ │ ├── prompts │ │ │ │ └── prompt-registry.ts │ │ │ ├── tools │ │ │ │ ├── ds │ │ │ │ │ ├── component │ │ │ │ │ │ ├── get-deprecated-css-classes.tool.ts │ │ │ │ │ │ ├── get-ds-component-data.tool.ts │ │ │ │ │ │ ├── list-ds-components.tool.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ ├── deprecated-css-helpers.ts │ │ │ │ │ │ ├── doc-helpers.ts │ │ │ │ │ │ ├── metadata-helpers.ts │ │ │ │ │ │ └── paths-helpers.ts │ │ │ │ │ ├── component-contract │ │ │ │ │ │ ├── builder │ │ │ │ │ │ │ ├── build-component-contract.tool.ts │ │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ │ ├── schema.ts │ │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ │ ├── spec │ │ │ │ │ │ │ │ ├── css-match.spec.ts │ │ │ │ │ │ │ │ ├── dom-slots.extractor.spec.ts │ │ │ │ │ │ │ │ ├── element-helpers.spec.ts │ │ │ │ │ │ │ │ ├── inline-styles.collector.spec.ts │ │ │ │ │ │ │ │ ├── meta.generator.spec.ts │ │ │ │ │ │ │ │ ├── public-api.extractor.spec.ts │ │ │ │ │ │ │ │ ├── styles.collector.spec.ts │ │ │ │ │ │ │ │ └── typescript-analyzer.spec.ts │ │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── build-contract.ts │ │ │ │ │ │ │ ├── css-match.ts │ │ │ │ │ │ │ ├── dom-slots.extractor.ts │ │ │ │ │ │ │ ├── element-helpers.ts │ │ │ │ │ │ │ ├── inline-styles.collector.ts │ │ │ │ │ │ │ ├── meta.generator.ts │ │ │ │ │ │ │ ├── public-api.extractor.ts │ │ │ │ │ │ │ ├── styles.collector.ts │ │ │ │ │ │ │ └── typescript-analyzer.ts │ │ │ │ │ │ ├── diff │ │ │ │ │ │ │ ├── diff-component-contract.tool.ts │ │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ │ └── schema.ts │ │ │ │ │ │ │ ├── spec │ │ │ │ │ │ │ │ ├── diff-utils.spec.ts │ │ │ │ │ │ │ │ └── dom-path-utils.spec.ts │ │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── diff-utils.ts │ │ │ │ │ │ │ └── dom-path-utils.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── list │ │ │ │ │ │ │ ├── list-component-contracts.tool.ts │ │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ │ ├── schema.ts │ │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ │ ├── spec │ │ │ │ │ │ │ │ └── contract-list-utils.spec.ts │ │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ └── contract-list-utils.ts │ │ │ │ │ │ └── shared │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── spec │ │ │ │ │ │ │ └── contract-file-ops.spec.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ └── contract-file-ops.ts │ │ │ │ │ ├── component-usage-graph │ │ │ │ │ │ ├── build-component-usage-graph.tool.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ ├── config.ts │ │ │ │ │ │ │ ├── schema.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ ├── angular-parser.ts │ │ │ │ │ │ ├── component-helpers.ts │ │ │ │ │ │ ├── component-usage-graph-builder.ts │ │ │ │ │ │ ├── path-resolver.ts │ │ │ │ │ │ └── unified-ast-analyzer.ts │ │ │ │ │ ├── ds.tools.ts │ │ │ │ │ ├── project │ │ │ │ │ │ ├── get-project-dependencies.tool.ts │ │ │ │ │ │ ├── report-deprecated-css.tool.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ ├── dependencies-helpers.ts │ │ │ │ │ │ └── styles-report-helpers.ts │ │ │ │ │ ├── report-violations │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ ├── schema.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── report-all-violations.tool.ts │ │ │ │ │ │ └── report-violations.tool.ts │ │ │ │ │ ├── shared │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ ├── input-schemas.model.ts │ │ │ │ │ │ │ └── schema-helpers.ts │ │ │ │ │ │ ├── utils │ │ │ │ │ │ │ ├── component-validation.ts │ │ │ │ │ │ │ ├── cross-platform-path.ts │ │ │ │ │ │ │ ├── handler-helpers.ts │ │ │ │ │ │ │ ├── output.utils.ts │ │ │ │ │ │ │ └── regex-helpers.ts │ │ │ │ │ │ └── violation-analysis │ │ │ │ │ │ ├── base-analyzer.ts │ │ │ │ │ │ ├── coverage-analyzer.ts │ │ │ │ │ │ ├── formatters.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── tools.ts │ │ │ │ ├── schema.ts │ │ │ │ ├── tools.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ └── validation │ │ │ ├── angular-mcp-server-options.schema.ts │ │ │ ├── ds-components-file-loader.validation.ts │ │ │ ├── ds-components-file.validation.ts │ │ │ ├── ds-components.schema.ts │ │ │ └── file-existence.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.tsbuildinfo │ │ └── vitest.config.mts │ ├── minimal-repo │ │ └── packages │ │ ├── application │ │ │ ├── angular.json │ │ │ ├── code-pushup.config.ts │ │ │ ├── src │ │ │ │ ├── app │ │ │ │ │ ├── app.component.ts │ │ │ │ │ ├── app.config.ts │ │ │ │ │ ├── app.routes.ts │ │ │ │ │ ├── components │ │ │ │ │ │ ├── refactoring-tests │ │ │ │ │ │ │ ├── bad-alert-tooltip-input.component.ts │ │ │ │ │ │ │ ├── bad-alert.component.ts │ │ │ │ │ │ │ ├── bad-button-dropdown.component.ts │ │ │ │ │ │ │ ├── bad-document.component.ts │ │ │ │ │ │ │ ├── bad-global-this.component.ts │ │ │ │ │ │ │ ├── bad-mixed-external-assets.component.css │ │ │ │ │ │ │ ├── bad-mixed-external-assets.component.html │ │ │ │ │ │ │ ├── bad-mixed-external-assets.component.ts │ │ │ │ │ │ │ ├── bad-mixed-not-standalone.component.ts │ │ │ │ │ │ │ ├── bad-mixed.component.ts │ │ │ │ │ │ │ ├── bad-mixed.module.ts │ │ │ │ │ │ │ ├── bad-modal-progress.component.ts │ │ │ │ │ │ │ ├── bad-this-window-document.component.ts │ │ │ │ │ │ │ ├── bad-window.component.ts │ │ │ │ │ │ │ ├── complex-components │ │ │ │ │ │ │ │ ├── first-case │ │ │ │ │ │ │ │ │ ├── dashboard-demo.component.html │ │ │ │ │ │ │ │ │ ├── dashboard-demo.component.scss │ │ │ │ │ │ │ │ │ ├── dashboard-demo.component.ts │ │ │ │ │ │ │ │ │ ├── dashboard-header.component.html │ │ │ │ │ │ │ │ │ ├── dashboard-header.component.scss │ │ │ │ │ │ │ │ │ └── dashboard-header.component.ts │ │ │ │ │ │ │ │ ├── second-case │ │ │ │ │ │ │ │ │ ├── complex-badge-widget.component.scss │ │ │ │ │ │ │ │ │ ├── complex-badge-widget.component.ts │ │ │ │ │ │ │ │ │ └── complex-widget-demo.component.ts │ │ │ │ │ │ │ │ └── third-case │ │ │ │ │ │ │ │ ├── product-card.component.scss │ │ │ │ │ │ │ │ ├── product-card.component.ts │ │ │ │ │ │ │ │ └── product-showcase.component.ts │ │ │ │ │ │ │ ├── group-1 │ │ │ │ │ │ │ │ ├── bad-mixed-1.component.ts │ │ │ │ │ │ │ │ ├── bad-mixed-1.module.ts │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-1.component.css │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-1.component.html │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-1.component.ts │ │ │ │ │ │ │ │ └── bad-mixed-not-standalone-1.component.ts │ │ │ │ │ │ │ ├── group-2 │ │ │ │ │ │ │ │ ├── bad-mixed-2.component.ts │ │ │ │ │ │ │ │ ├── bad-mixed-2.module.ts │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-2.component.css │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-2.component.html │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-2.component.ts │ │ │ │ │ │ │ │ └── bad-mixed-not-standalone-2.component.ts │ │ │ │ │ │ │ ├── group-3 │ │ │ │ │ │ │ │ ├── bad-mixed-3.component.spec.ts │ │ │ │ │ │ │ │ ├── bad-mixed-3.component.ts │ │ │ │ │ │ │ │ ├── bad-mixed-3.module.ts │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-3.component.css │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-3.component.html │ │ │ │ │ │ │ │ ├── bad-mixed-external-assets-3.component.ts │ │ │ │ │ │ │ │ ├── bad-mixed-not-standalone-3.component.ts │ │ │ │ │ │ │ │ └── lazy-loader-3.component.ts │ │ │ │ │ │ │ └── group-4 │ │ │ │ │ │ │ ├── multi-violation-test.component.html │ │ │ │ │ │ │ ├── multi-violation-test.component.scss │ │ │ │ │ │ │ └── multi-violation-test.component.ts │ │ │ │ │ │ └── validation-tests │ │ │ │ │ │ ├── circular-dependency.component.ts │ │ │ │ │ │ ├── external-files-missing.component.ts │ │ │ │ │ │ ├── invalid-lifecycle.component.ts │ │ │ │ │ │ ├── invalid-pipe-usage.component.ts │ │ │ │ │ │ ├── invalid-template-syntax.component.ts │ │ │ │ │ │ ├── missing-imports.component.ts │ │ │ │ │ │ ├── missing-method.component.ts │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── standalone-module-conflict.component.ts │ │ │ │ │ │ ├── standalone-module-conflict.module.ts │ │ │ │ │ │ ├── template-reference-error.component.ts │ │ │ │ │ │ ├── type-mismatch.component.ts │ │ │ │ │ │ ├── valid.component.ts │ │ │ │ │ │ ├── wrong-decorator-usage.component.ts │ │ │ │ │ │ └── wrong-property-binding.component.ts │ │ │ │ │ └── styles │ │ │ │ │ ├── bad-global-styles.scss │ │ │ │ │ ├── base │ │ │ │ │ │ ├── _reset.scss │ │ │ │ │ │ └── base.scss │ │ │ │ │ ├── components │ │ │ │ │ │ └── components.scss │ │ │ │ │ ├── extended-deprecated-styles.scss │ │ │ │ │ ├── layout │ │ │ │ │ │ └── layout.scss │ │ │ │ │ ├── new-styles-1.scss │ │ │ │ │ ├── new-styles-10.scss │ │ │ │ │ ├── new-styles-2.scss │ │ │ │ │ ├── new-styles-3.scss │ │ │ │ │ ├── new-styles-4.scss │ │ │ │ │ ├── new-styles-5.scss │ │ │ │ │ ├── new-styles-6.scss │ │ │ │ │ ├── new-styles-7.scss │ │ │ │ │ ├── new-styles-8.scss │ │ │ │ │ ├── new-styles-9.scss │ │ │ │ │ ├── themes │ │ │ │ │ │ └── themes.scss │ │ │ │ │ └── utilities │ │ │ │ │ └── utilities.scss │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── styles.css │ │ │ ├── tsconfig.app.json │ │ │ ├── tsconfig.json │ │ │ └── tsconfig.spec.json │ │ └── design-system │ │ ├── component-options.mjs │ │ ├── storybook │ │ │ └── card │ │ │ └── card-tabs │ │ │ └── overview.mdx │ │ ├── storybook-host-app │ │ │ └── src │ │ │ └── components │ │ │ ├── badge │ │ │ │ ├── badge-tabs │ │ │ │ │ ├── api.mdx │ │ │ │ │ ├── examples.mdx │ │ │ │ │ └── overview.mdx │ │ │ │ ├── badge.component.mdx │ │ │ │ └── badge.component.stories.ts │ │ │ ├── modal │ │ │ │ ├── demo-cdk-dialog-cmp.component.ts │ │ │ │ ├── demo-modal-cmp.component.ts │ │ │ │ ├── modal-tabs │ │ │ │ │ ├── api.mdx │ │ │ │ │ ├── examples.mdx │ │ │ │ │ └── overview.mdx │ │ │ │ ├── modal.component.mdx │ │ │ │ └── modal.component.stories.ts │ │ │ └── segmented-control │ │ │ ├── segmented-control-tabs │ │ │ │ ├── api.mdx │ │ │ │ ├── examples.mdx │ │ │ │ └── overview.mdx │ │ │ ├── segmented-control.component.mdx │ │ │ └── segmented-control.component.stories.ts │ │ └── ui │ │ ├── badge │ │ │ ├── package.json │ │ │ ├── project.json │ │ │ └── src │ │ │ └── badge.component.ts │ │ ├── modal │ │ │ ├── package.json │ │ │ ├── project.json │ │ │ └── src │ │ │ ├── modal-content.component.ts │ │ │ ├── modal-header │ │ │ │ └── modal-header.component.ts │ │ │ ├── modal-header-drag │ │ │ │ └── modal-header-drag.component.ts │ │ │ └── modal.component.ts │ │ ├── rx-host-listener │ │ │ ├── package.json │ │ │ ├── project.json │ │ │ └── src │ │ │ └── rx-host-listener.ts │ │ └── segmented-control │ │ ├── package.json │ │ ├── project.json │ │ └── src │ │ ├── segmented-control.component.html │ │ ├── segmented-control.component.ts │ │ ├── segmented-control.token.ts │ │ └── segmented-option.component.ts │ └── shared │ ├── angular-ast-utils │ │ ├── .spec.swcrc │ │ ├── ai │ │ │ ├── API.md │ │ │ ├── EXAMPLES.md │ │ │ └── FUNCTIONS.md │ │ ├── docs │ │ │ └── angular-component-tree.md │ │ ├── eslint.config.mjs │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── constants.ts │ │ │ ├── decorator-config.visitor.inline-styles.spec.ts │ │ │ ├── decorator-config.visitor.spec.ts │ │ │ ├── decorator-config.visitor.ts │ │ │ ├── parse-component.ts │ │ │ ├── schema.ts │ │ │ ├── styles │ │ │ │ └── utils.ts │ │ │ ├── template │ │ │ │ ├── noop-tmpl-visitor.ts │ │ │ │ ├── template.walk.ts │ │ │ │ ├── utils.spec.ts │ │ │ │ ├── utils.ts │ │ │ │ └── utils.unit.test.ts │ │ │ ├── ts.walk.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.spec.json │ │ └── vitest.config.mts │ ├── DEPENDENCIES.md │ ├── ds-component-coverage │ │ ├── .spec.swcrc │ │ ├── ai │ │ │ ├── API.md │ │ │ ├── EXAMPLES.md │ │ │ └── FUNCTIONS.md │ │ ├── docs │ │ │ ├── examples │ │ │ │ ├── report.json │ │ │ │ └── report.md │ │ │ ├── images │ │ │ │ └── report-overview.png │ │ │ └── README.md │ │ ├── jest.config.ts │ │ ├── mocks │ │ │ └── fixtures │ │ │ └── e2e │ │ │ ├── asset-location │ │ │ │ ├── code-pushup.config.ts │ │ │ │ ├── inl-styl-inl-tmpl │ │ │ │ │ └── inl-styl-inl-tmpl.component.ts │ │ │ │ ├── inl-styl-url-tmpl │ │ │ │ │ ├── inl-styl-url-tmpl.component.html │ │ │ │ │ └── inl-styl-url-tmpl.component.ts │ │ │ │ ├── multi-url-styl-inl-tmpl │ │ │ │ │ ├── multi-url-styl-inl-tmpl-1.component.css │ │ │ │ │ ├── multi-url-styl-inl-tmpl-2.component.css │ │ │ │ │ └── multi-url-styl-inl-tmpl.component.ts │ │ │ │ ├── url-styl-inl-tmpl │ │ │ │ │ ├── url-styl-inl-tmpl.component.css │ │ │ │ │ └── url-styl-inl-tmpl.component.ts │ │ │ │ ├── url-styl-single-inl-tmpl │ │ │ │ │ ├── url-styl-inl-tmpl.component.ts │ │ │ │ │ └── url-styl-single-inl-tmpl.component.css │ │ │ │ └── url-styl-url-tmpl │ │ │ │ ├── inl-styl-url-tmpl.component.css │ │ │ │ ├── inl-styl-url-tmpl.component.html │ │ │ │ └── inl-styl-url-tmpl.component.ts │ │ │ ├── demo │ │ │ │ ├── code-pushup.config.ts │ │ │ │ ├── prompt.md │ │ │ │ └── src │ │ │ │ ├── bad-button-dropdown.component.ts │ │ │ │ ├── bad-modal-progress.component.ts │ │ │ │ ├── mixed-external-assets.component.css │ │ │ │ ├── mixed-external-assets.component.html │ │ │ │ ├── mixed-external-assets.component.ts │ │ │ │ └── sub-folder-1 │ │ │ │ ├── bad-alert.component.ts │ │ │ │ ├── button.component.ts │ │ │ │ └── sub-folder-2 │ │ │ │ ├── bad-alert-tooltip-input.component.ts │ │ │ │ └── bad-mixed.component.ts │ │ │ ├── line-number │ │ │ │ ├── code-pushup.config.ts │ │ │ │ ├── inl-styl-single.component.ts │ │ │ │ ├── inl-styl-span.component.ts │ │ │ │ ├── inl-tmpl-single.component.ts │ │ │ │ ├── inl-tmpl-span.component.ts │ │ │ │ ├── url-style │ │ │ │ │ ├── url-styl-single.component.css │ │ │ │ │ ├── url-styl-single.component.ts │ │ │ │ │ ├── url-styl-span.component.css │ │ │ │ │ └── url-styl-span.component.ts │ │ │ │ └── url-tmpl │ │ │ │ ├── url-tmpl-single.component.html │ │ │ │ ├── url-tmpl-single.component.ts │ │ │ │ ├── url-tmpl-span.component.html │ │ │ │ └── url-tmpl-span.component.ts │ │ │ ├── style-format │ │ │ │ ├── code-pushup.config.ts │ │ │ │ ├── inl-css.component.ts │ │ │ │ ├── inl-scss.component.ts │ │ │ │ ├── styles.css │ │ │ │ ├── styles.scss │ │ │ │ ├── url-css.component.ts │ │ │ │ └── url-scss.component.ts │ │ │ └── template-syntax │ │ │ ├── class-attribute.component.ts │ │ │ ├── class-binding.component.ts │ │ │ ├── code-pushup.config.ts │ │ │ └── ng-class-binding.component.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── core.config.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── constants.ts │ │ │ ├── ds-component-coverage.plugin.ts │ │ │ ├── runner │ │ │ │ ├── audits │ │ │ │ │ └── ds-coverage │ │ │ │ │ ├── class-definition.utils.ts │ │ │ │ │ ├── class-definition.visitor.ts │ │ │ │ │ ├── class-definition.visitor.unit.test.ts │ │ │ │ │ ├── class-usage.utils.ts │ │ │ │ │ ├── class-usage.visitor.spec.ts │ │ │ │ │ ├── class-usage.visitor.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── ds-coverage.audit.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── create-runner.ts │ │ │ │ └── schema.ts │ │ │ └── utils.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.spec.json │ │ └── vitest.config.mts │ ├── LLMS.md │ ├── models │ │ ├── ai │ │ │ ├── API.md │ │ │ ├── EXAMPLES.md │ │ │ └── FUNCTIONS.md │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── cli.ts │ │ │ ├── diagnostics.ts │ │ │ └── mcp.ts │ │ ├── tsconfig.json │ │ └── tsconfig.lib.json │ ├── styles-ast-utils │ │ ├── .spec.swcrc │ │ ├── ai │ │ │ ├── API.md │ │ │ ├── EXAMPLES.md │ │ │ └── FUNCTIONS.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── postcss-safe-parser.d.ts │ │ │ ├── styles-ast-utils.spec.ts │ │ │ ├── styles-ast-utils.ts │ │ │ ├── stylesheet.parse.ts │ │ │ ├── stylesheet.parse.unit.test.ts │ │ │ ├── stylesheet.visitor.ts │ │ │ ├── stylesheet.walk.ts │ │ │ ├── types.ts │ │ │ ├── utils.ts │ │ │ └── utils.unit.test.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.spec.json │ │ └── vitest.config.mts │ ├── typescript-ast-utils │ │ ├── .spec.swcrc │ │ ├── ai │ │ │ ├── API.md │ │ │ ├── EXAMPLES.md │ │ │ └── FUNCTIONS.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── constants.ts │ │ │ └── utils.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.spec.json │ │ └── vitest.config.mts │ └── utils │ ├── .spec.swcrc │ ├── ai │ │ ├── API.md │ │ ├── EXAMPLES.md │ │ └── FUNCTIONS.md │ ├── package.json │ ├── README.md │ ├── src │ │ ├── index.ts │ │ └── lib │ │ ├── execute-process.ts │ │ ├── execute-process.unit.test.ts │ │ ├── file │ │ │ ├── default-export-loader.spec.ts │ │ │ ├── default-export-loader.ts │ │ │ ├── file.resolver.ts │ │ │ └── find-in-file.ts │ │ ├── format-command-log.integration.test.ts │ │ ├── format-command-log.ts │ │ ├── logging.ts │ │ └── utils.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── vite.config.ts │ └── vitest.config.mts ├── README.md ├── testing │ ├── setup │ │ ├── eslint.config.mjs │ │ ├── eslint.next.config.mjs │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.d.ts │ │ │ ├── index.mjs │ │ │ └── memfs.constants.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.spec.json │ │ ├── vitest.config.mts │ │ └── vitest.integration.config.mts │ ├── utils │ │ ├── eslint.config.mjs │ │ ├── eslint.next.config.mjs │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── constants.ts │ │ │ ├── e2e-setup.ts │ │ │ ├── execute-process-helper.mock.ts │ │ │ ├── execute-process.mock.mjs │ │ │ ├── os-agnostic-paths.ts │ │ │ ├── os-agnostic-paths.unit.test.ts │ │ │ ├── source-file-from.code.ts │ │ │ └── string.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ ├── tsconfig.spec.json │ │ ├── vite.config.ts │ │ ├── vitest.config.mts │ │ └── vitest.integration.config.mts │ └── vitest-setup │ ├── eslint.config.mjs │ ├── eslint.next.config.mjs │ ├── package.json │ ├── README.md │ ├── src │ │ ├── index.ts │ │ └── lib │ │ ├── configuration.ts │ │ └── fs-memfs.setup-file.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── vite.config.ts │ ├── vitest.config.mts │ └── vitest.integration.config.mts ├── tools │ ├── nx-advanced-profile.bin.js │ ├── nx-advanced-profile.js │ ├── nx-advanced-profile.postinstall.js │ └── perf_hooks.patch.js ├── tsconfig.base.json ├── tsconfig.json └── vitest.workspace.ts ``` # Files -------------------------------------------------------------------------------- /packages/.gitkeep: -------------------------------------------------------------------------------- ``` 1 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp/src/assets/.gitkeep: -------------------------------------------------------------------------------- ``` 1 | ``` -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- ``` 1 | 22.14.0 2 | ``` -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- ``` 1 | { 2 | "singleQuote": true 3 | } 4 | ``` -------------------------------------------------------------------------------- /.aiignore: -------------------------------------------------------------------------------- ``` 1 | # An .aiignore file follows the same syntax as a .gitignore file. 2 | # .gitignore documentation: https://git-scm.com/docs/gitignore 3 | 4 | # you can ignore files 5 | .DS_Store 6 | *.log 7 | *.tmp 8 | 9 | # or folders 10 | dist/ 11 | build/ 12 | out/ 13 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/.spec.swcrc: -------------------------------------------------------------------------------- ``` 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "es6" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [] 22 | } 23 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/.spec.swcrc: -------------------------------------------------------------------------------- ``` 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "es6" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [] 22 | } 23 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/.spec.swcrc: -------------------------------------------------------------------------------- ``` 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "es6" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [] 22 | } 23 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/.spec.swcrc: -------------------------------------------------------------------------------- ``` 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "es6" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [] 22 | } 23 | ``` -------------------------------------------------------------------------------- /packages/shared/utils/.spec.swcrc: -------------------------------------------------------------------------------- ``` 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "es6" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [] 22 | } 23 | ``` -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- ``` 1 | # Add files here to ignore them from prettier formatting 2 | /dist 3 | **/dist 4 | 5 | /coverage 6 | /.nx/cache 7 | /.nx/workspace-data 8 | packages/minimal-repo/packages/application 9 | 10 | *.md 11 | *.mdx 12 | **/*.md 13 | **/*.mdx 14 | 15 | # Additional file types that should be ignored 16 | *.mdc 17 | **/*.mdc 18 | .aiignore 19 | .gitignore 20 | .nvmrc 21 | .prettierignore 22 | *.gitkeep 23 | **/*.gitkeep 24 | *.swcrc 25 | **/*.swcrc 26 | *.tsbuildinfo 27 | **/*.tsbuildinfo 28 | *.png 29 | *.jpg 30 | *.jpeg 31 | *.gif 32 | *.svg 33 | **/*.png 34 | **/*.jpg 35 | **/*.jpeg 36 | **/*.gif 37 | **/*.svg ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` 1 | # See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | .nx/cache 42 | .nx/workspace-data 43 | 44 | test-output 45 | 46 | vite.config.*.timestamp* 47 | vitest.config.*.timestamp* 48 | 49 | .code-pushup 50 | 51 | .cursor/rules/nx-rules.mdc 52 | .cursor/mcp.json 53 | .github/instructions/nx.instructions.md 54 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/docs/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Design System Component Coverage 2 | 3 | This plugin checks if the design system is used correctly across a project. 4 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # angular-mcp-server 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build angular-mcp-server` to build the library. 8 | ``` -------------------------------------------------------------------------------- /packages/shared/utils/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # utils 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build utils` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test utils` to execute the unit tests via [Jest](https://jestjs.io). 12 | ``` -------------------------------------------------------------------------------- /packages/shared/models/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # models 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build models` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test models` to execute the unit tests via [Jest](https://jestjs.io). 12 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # styles-ast-utils 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build styles-ast-utils` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test styles-ast-utils` to execute the unit tests via [Jest](https://jestjs.io). 12 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # angular-ast-utils 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build angular-ast-utils` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test angular-ast-utils` to execute the unit tests via [Jest](https://jestjs.io). 12 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # typescript-ast-utils 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build typescript-ast-utils` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test typescript-ast-utils` to execute the unit tests via [Jest](https://jestjs.io). 12 | ``` -------------------------------------------------------------------------------- /testing/utils/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # testing-utils 2 | 3 | This library provides a set of helper functions for testing. 4 | 5 | The many content divides into: 6 | 7 | - constants 8 | - mock helper 9 | - utils for OS dependent APIs 10 | 11 | ## Building 12 | 13 | Run `nx build testing-utils` to build the library. 14 | 15 | ## Running unit tests 16 | 17 | Run `nx test testing-utils` to execute the unit tests via [Vitest](https://vitest.dev/). 18 | ``` -------------------------------------------------------------------------------- /testing/setup/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # testing-vitest-setup 2 | 3 | This library provides a set of setup scripts for testing. 4 | As this package is never directly referenced, but only it's files it does not maintain a `index.ts` entry point. 5 | 6 | ## The many content divides into: 7 | 8 | - **Setup files** - obey to the naming pattern `<purpose>-setup-file.ts` and should be used in a `vite.config.ts` testing config under the `setupFiles` property. 9 | - **Global setup files** - obey to the naming pattern `<purpose>-global-setup-file.ts` and should be used in a `vite.config.ts` testing config under the `globalSetup` property. 10 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # testing-vitest-setup 2 | 3 | This library provides a set of setup scripts for testing. 4 | As this package is never directly referenced, but only it's files it does not maintain a `index.ts` entry point. 5 | 6 | ## The many content divides into: 7 | 8 | - **Setup files** - obey to the naming pattern `<purpose>-setup-file.ts` and should be used in a `vite.config.ts` testing config under the `setupFiles` property. 9 | - **Global setup files** - obey to the naming pattern `<purpose>-global-setup-file.ts` and should be used in a `vite.config.ts` testing config under the `globalSetup` property. 10 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Validation Test Components 2 | 3 | This folder contains various Angular components designed to test different types of build and validation errors. 4 | 5 | ## Error Cases 6 | 7 | - `missing-method.component.ts` - Template calls non-existing method `nonExistentMethod()` 8 | - `wrong-property-binding.component.ts` - Template binds to non-existing property `nonExistentProperty` 9 | - `invalid-template-syntax.component.ts` - Invalid template syntax with unclosed tags and malformed bindings 10 | - `missing-imports.component.ts` - Uses Angular features without proper imports (FormsModule, CommonModule) 11 | - `circular-dependency.component.ts` - Creates circular dependency by importing itself 12 | - `invalid-lifecycle.component.ts` - Implements lifecycle interfaces incorrectly 13 | - `wrong-decorator-usage.component.ts` - Uses @Input/@Output decorators incorrectly 14 | - `template-reference-error.component.ts` - Template references undefined variables and methods 15 | - `invalid-pipe-usage.component.ts` - Uses non-existent pipes and incorrect pipe syntax 16 | - `type-mismatch.component.ts` - Type mismatches between template and component properties 17 | - `standalone-module-conflict.component.ts` - Standalone component incorrectly declared in module 18 | - `external-files-missing.component.ts` - References non-existent external template and style files 19 | 20 | ## Valid Component 21 | 22 | - `valid.component.ts` - Fully valid standalone component for comparison ``` -------------------------------------------------------------------------------- /packages/angular-mcp/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Angular Toolkit MCP 2 | 3 | A Model Context Protocol (MCP) server that provides Angular project analysis and refactoring capabilities. This server enables LLMs to analyze Angular projects for component usage patterns, dependency analysis, code quality issues, and provides automated refactoring assistance. 4 | 5 | ## Installation 6 | 7 | No installation required! Run directly with npx: 8 | 9 | ```bash 10 | npx @push-based/angular-toolkit-mcp@latest --workspaceRoot=/path/to/workspace --ds.uiRoot=packages/ui 11 | ``` 12 | 13 | ## Configuration 14 | 15 | Add the server to your MCP client configuration (e.g., Claude Desktop, Cursor, Copilot, Windsurf): 16 | 17 | ```json 18 | { 19 | "mcpServers": { 20 | "angular-toolkit": { 21 | "command": "npx", 22 | "args": [ 23 | "@push-based/angular-toolkit-mcp@latest", 24 | "--workspaceRoot=/absolute/path/to/your/angular/workspace", 25 | "--ds.uiRoot=packages/ui", 26 | "--ds.storybookDocsRoot=storybook/docs", 27 | "--ds.deprecatedCssClassesPath=design-system/component-options.mjs" 28 | ] 29 | } 30 | } 31 | } 32 | ``` 33 | 34 | ### Configuration Parameters 35 | 36 | #### Required Parameters 37 | 38 | | Parameter | Type | Description | Example | 39 | |-----------|------|-------------|---------| 40 | | `workspaceRoot` | Absolute path | Root directory of your Angular workspace | `/Users/dev/my-angular-app` | 41 | | `ds.uiRoot` | Relative path | Directory containing UI components | `packages/ui` | 42 | 43 | #### Optional Parameters 44 | 45 | | Parameter | Type | Description | Example | 46 | |-----------|------|-------------|---------| 47 | | `ds.storybookDocsRoot` | Relative path | Root directory containing Storybook documentation | `storybook/docs` | 48 | | `ds.deprecatedCssClassesPath` | Relative path | JavaScript file mapping deprecated CSS classes | `design-system/component-options.mjs` | 49 | 50 | ## Key Features 51 | 52 | - **Component Analysis**: Detect deprecated CSS classes and component usage violations 53 | - **Safe Refactoring**: Generate contracts for safe component refactoring with breaking change detection 54 | - **Dependency Mapping**: Map component dependencies across modules, templates, and styles 55 | - **ESLint Integration**: Lint Angular files with automatic ESLint configuration discovery 56 | - **Project Analysis**: Analyze buildable/publishable libraries and validate import paths 57 | - **Component Documentation**: Retrieve component data and documentation, list available components 58 | 59 | ## Available Tools 60 | 61 | ### Component Analysis 62 | - `report-violations` - Report deprecated CSS usage in a directory 63 | - `report-deprecated-css` - Report deprecated CSS classes found in styling files 64 | - `get-deprecated-css-classes` - List deprecated CSS classes for a component 65 | - `list-ds-components` - List all available Design System components 66 | - `get-ds-component-data` - Get component data including implementation and documentation 67 | - `build-component-usage-graph` - Map component imports across the project 68 | 69 | ### Component Contracts 70 | - `build_component_contract` - Generate a static surface contract for a component 71 | - `diff_component_contract` - Compare before/after contracts for breaking changes 72 | - `list_component_contracts` - List all available component contracts 73 | 74 | ### Project Analysis 75 | - `get-project-dependencies` - Analyze project dependencies and library configuration 76 | - `lint-changes` - Lint changed Angular files using ESLint rules 77 | 78 | ## Requirements 79 | 80 | - Node.js version 18 or higher 81 | 82 | ## Documentation 83 | 84 | For comprehensive documentation, guides, and workflows, see the [full documentation](https://github.com/push-based/angular-toolkit-mcp). 85 | 86 | ## License 87 | 88 | MIT License - see the [LICENSE](https://github.com/push-based/angular-toolkit-mcp/blob/main/LICENSE) file for details. 89 | 90 | --- 91 | 92 | <div align="center"> 93 | <p><strong>Sponsored by Entain</strong></p> 94 | </div> 95 | ``` -------------------------------------------------------------------------------- /.cursor/flows/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Cursor Flows 2 | 3 | This directory contains AI-assisted workflow templates (flows) for Angular component refactoring and design system migration tasks. These flows are designed to work with Cursor IDE's rule system to provide structured, step-by-step guidance for complex refactoring operations. 4 | 5 | ## What are Flows? 6 | 7 | Flows are collections of rule files (.mdc) that guide the AI through multi-step processes. Each flow contains: 8 | - **Rule files (.mdc)**: Step-by-step instructions for the AI 9 | - **Documentation**: Supporting materials and best practices 10 | - **Templates**: Reusable patterns and examples 11 | 12 | ## Available Flows 13 | 14 | ### 1. Component Refactoring Flow 15 | **Location:** `component-refactoring/` 16 | **Purpose:** Improve individual Angular components according to modern best practices 17 | 18 | **Files:** 19 | - `01-review-component.mdc` - Analyze component and create improvement plan 20 | - `02-refactor-component.mdc` - Execute refactoring checklist 21 | - `03-validate-component.mdc` - Verify improvements through contract comparison 22 | - `angular-20.md` - Angular best practices reference 23 | 24 | **Use Case:** When you need to modernize a single component's code quality, performance, or maintainability. 25 | 26 | ### 2. Design System Refactoring Flow 27 | **Location:** `ds-refactoring-flow/` 28 | **Purpose:** Migrate components from deprecated design system patterns to modern alternatives 29 | 30 | **Flow Options:** 31 | 32 | **Option A: Targeted Approach** (recommended for focused, incremental migrations) 33 | - `01-find-violations.mdc` - Identify specific deprecated component usage 34 | - `02-plan-refactoring.mdc` - Create detailed migration strategy for specific cases 35 | 36 | **Option B: Comprehensive Approach** (recommended for large-scale migrations) 37 | - `01b-find-all-violations.mdc` - Scan entire codebase, group by folders, select subfolder for detailed analysis 38 | - `02b-plan-refactoring-for-all-violations.mdc` - Create comprehensive migration plan for all violations in scope 39 | 40 | **Continuation Steps** (used with both approaches): 41 | - `03-non-viable-cases.mdc` - Handle non-migratable components by marking them for exclusion 42 | - `03-fix-violations.mdc` - Execute code changes 43 | - `04-validate-changes.mdc` - Verify improvements through contract comparison 44 | - `05-prepare-report.mdc` - Generate testing checklists and documentation 45 | - `clean-global-styles.mdc` - Independent analysis of deprecated CSS usage 46 | 47 | **Choosing Your Approach:** 48 | - **Targeted (01 → 02)**: Use when working on specific components or small sets of violations. Provides focused analysis and incremental progress. 49 | - **Comprehensive (01b → 02b)**: Use when planning large-scale migrations across multiple folders. Provides broad overview first, then detailed planning for selected scope. 50 | 51 | **Special Handling:** 52 | - **Non-Viable Cases**: When components are identified as non-viable during the planning step, use `03-non-viable-cases.mdc` instead of proceeding with the normal fix violations step. This marks components with special prefixes (`after-migration-[ORIGINAL_CLASS]`) to exclude them from future violation reports. 53 | 54 | **Use Cases:** 55 | - **Targeted Flow**: Incremental migration of specific components or small violation sets 56 | - **Comprehensive Flow**: Large-scale migration planning across multiple directories 57 | - **Non-Viable Handling**: Alternative handling within either flow for legacy components that cannot be migrated 58 | 59 | ## How to Use Flows 60 | 61 | 1. Copy the desired flow's `.mdc` files to your `.cursor/rules/` directory 62 | 2. The rules will be automatically available in Cursor 63 | 3. Follow the flow documentation for step-by-step guidance 64 | 65 | ## Prerequisites 66 | 67 | Before using any flow, ensure you have: 68 | - **Cursor IDE** with MCP (Model Context Protocol) server connected 69 | - **Git branch** for your refactoring work 70 | - **Component files** accessible in your workspace 71 | - **Angular project** with proper TypeScript configuration 72 | 73 | ## Flow Process Overview 74 | 75 | Most flows follow a similar pattern: 76 | 1. **Analysis** - Review current state and identify issues 77 | 2. **Planning** - Create actionable improvement checklist 78 | 3. **Execution** - Implement changes systematically 79 | 4. **Validation** - Verify improvements and quality gates 80 | 5. **Reporting** - Document changes and results 81 | 82 | ## Quality Gates 83 | 84 | Flows include human review checkpoints to ensure: 85 | - ✅ Analysis accuracy 86 | - ✅ Refactoring plan approval 87 | - ✅ Code quality validation 88 | - ✅ Final acceptance 89 | 90 | ## Documentation 91 | 92 | For detailed information about each flow, see: 93 | - [Component Refactoring Flow](../../docs/component-refactoring-flow.md) 94 | - [Architecture & Design](../../docs/architecture-internal-design.md) 95 | - [Contracts Documentation](../../docs/contracts.md) ``` -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Angular MCP Toolkit Documentation 2 | 3 | Welcome to the Angular MCP (Model Context Protocol) Toolkit documentation! This toolkit provides tools for Angular development, focusing on design system migration, component refactoring, and code analysis. 4 | 5 | ## 📚 Documentation Overview 6 | 7 | This documentation is organized into several sections to help you get started quickly and understand the toolkit's capabilities: 8 | 9 | ### 🚀 Getting Started 10 | - **[Getting Started Guide](getting-started.md)** - Quick 5-minute setup guide to install and configure the Angular MCP server 11 | 12 | ### 🔧 Using the Tools 13 | - **[Tools Reference](tools.md)** - Comprehensive guide to all available AI tools for design system migration and analysis 14 | - **[Component Refactoring Flow](component-refactoring-flow.md)** - 3-step AI-assisted process for improving individual Angular components 15 | - **[Design System Refactoring Flow](ds-refactoring-flow.md)** - 5-step automated workflow for migrating legacy components to design system 16 | 17 | ### 📋 Advanced Features 18 | - **[Component Contracts](contracts.md)** - System for breaking change detection and refactoring validation 19 | - **[Writing Custom Tools](writing-custom-tools.md)** - Guide for developers to create new MCP tools 20 | 21 | ### 🏗️ Architecture & Development 22 | - **[Architecture & Internal Design](architecture-internal-design.md)** - Technical details for backend developers and tool authors 23 | 24 | ## 🎯 Quick Navigation 25 | 26 | ### For New Users 27 | 1. Start with **[Getting Started](getting-started.md)** to set up the toolkit 28 | 2. Review **[Tools Reference](tools.md)** to understand available capabilities 29 | 3. Try the **[Component Refactoring Flow](component-refactoring-flow.md)** for your first refactoring 30 | 31 | ### For Design System Migration 32 | 1. Use **[Design System Refactoring Flow](ds-refactoring-flow.md)** for systematic legacy component migration 33 | 2. When components are identified as non-viable during planning, use the **Non-Viable Cases handling** instead of normal fix violations step (requires developer review and approval) 34 | 3. Learn about **[Component Contracts](contracts.md)** for validation and safety 35 | 4. Reference **[Tools Reference](tools.md)** for specific tool details 36 | 37 | ### For Developers & Contributors 38 | 1. Read **[Architecture & Internal Design](architecture-internal-design.md)** to understand the system 39 | 2. Follow **[Writing Custom Tools](writing-custom-tools.md)** to extend functionality 40 | 3. Use **[Component Contracts](contracts.md)** for testing and validation 41 | 42 | ## 🔄 Workflow Integration 43 | 44 | The toolkit supports two main workflows: 45 | 46 | ### Individual Component Improvement 47 | ```mermaid 48 | graph LR 49 | A[Review Component] --> B[Refactor Component] --> C[Validate Component] 50 | B --> D[Human Review & Approval] 51 | C --> E[Quality Gate] 52 | ``` 53 | **Guide:** [Component Refactoring Flow](component-refactoring-flow.md) 54 | 55 | ### Design System Migration 56 | ```mermaid 57 | graph LR 58 | A[Find Violations] --> B[Plan Refactoring] --> B1{Viable?} 59 | B --> F[Human Review] 60 | B1 -->|Yes| C[Fix Violations] --> D[Validate Changes] --> E[Prepare Report] 61 | B1 -->|No + Dev Approval| B2[Non-Viable Cases<br/>Handling] 62 | C --> G[Quality Gate] 63 | D --> H[Final Validation] 64 | ``` 65 | **Guide:** [Design System Refactoring Flow](ds-refactoring-flow.md) 66 | 67 | ## 🛠️ Key Features 68 | 69 | - **AI-Powered Analysis** - Automated code analysis and refactoring suggestions 70 | - **Design System Integration** - Tools specifically designed for Angular design system adoption 71 | - **Contract-Based Validation** - Ensure refactoring safety with before/after comparisons 72 | - **Extensible Architecture** - Add custom tools and analysis capabilities 73 | - **Quality Gates** - Built-in checkpoints for human review and approval 74 | 75 | ## 📖 Document Relationships 76 | 77 | ``` 78 | Getting Started ──┐ 79 | ├─→ Tools Reference ──┐ 80 | │ ├─→ Component Refactoring Flow 81 | │ └─→ Design System Refactoring Flow 82 | │ │ 83 | └─→ Component Contracts ←──────────────┘ 84 | │ 85 | Writing Custom Tools ←──────────────────┘ 86 | │ 87 | Architecture & Internal Design ←────────┘ 88 | ``` 89 | 90 | ## 🤝 Contributing 91 | 92 | If you're interested in contributing to the toolkit: 93 | 94 | 1. Read the **[Architecture & Internal Design](architecture-internal-design.md)** for system understanding 95 | 2. Follow **[Writing Custom Tools](writing-custom-tools.md)** for adding new functionality 96 | 3. Use **[Component Contracts](contracts.md)** for testing your changes 97 | 98 | ## 📝 Need Help? 99 | 100 | - **Setup Issues**: Check [Getting Started](getting-started.md) 101 | - **Tool Usage**: Reference [Tools Reference](tools.md) 102 | - **Workflow Questions**: Review the appropriate flow documentation 103 | - **Technical Details**: Consult [Architecture & Internal Design](architecture-internal-design.md) 104 | 105 | --- 106 | 107 | <div align="center"> 108 | <p><strong>Sponsored by</strong></p> 109 | <img src="../assets/entain.png" alt="Entain" width="150"> 110 | </div> 111 | 112 | *This toolkit is designed to work with Cursor IDE, but should also be compatible with other AI-powered development environments like Windsurf or GitHub Copilot.* ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Angular Toolkit MCP 2 | 3 | [](https://www.npmjs.com/package/@push-based/angular-toolkit-mcp) 4 | 5 | A Model Context Protocol (MCP) server that provides Angular project analysis and refactoring capabilities. This server enables LLMs to analyze Angular projects for component usage patterns, dependency analysis, code quality issues, and provides automated refactoring assistance. 6 | 7 | ## Key Features 8 | 9 | - **Component Analysis**: Detect deprecated CSS classes and component usage violations 10 | - **Safe Refactoring**: Generate contracts for safe component refactoring with breaking change detection 11 | - **Dependency Mapping**: Map component dependencies across modules, templates, and styles 12 | - **ESLint Integration**: Lint Angular files with automatic ESLint configuration discovery 13 | - **Project Analysis**: Analyze buildable/publishable libraries and validate import paths 14 | - **Component Documentation**: Retrieve component data and documentation, list available components 15 | 16 | ## Use Cases 17 | 18 | - Angular project migration and refactoring 19 | - Component usage analysis and dependency mapping 20 | - Deprecated CSS class detection and reporting 21 | - Component contract generation for safe refactoring 22 | - Breaking change detection during component updates 23 | - Code quality analysis and improvement 24 | 25 | ## Quick Start 26 | 27 | Install and run via npx (no manual build required): 28 | 29 | ```json 30 | { 31 | "mcpServers": { 32 | "angular-toolkit": { 33 | "command": "npx", 34 | "args": [ 35 | "@push-based/angular-toolkit-mcp@latest", 36 | "--workspaceRoot=/absolute/path/to/your/angular/workspace", 37 | "--ds.uiRoot=packages/ui" 38 | ] 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | **Required Node.js version:** 18 or higher 45 | 46 | ## Configuration 47 | 48 | ### Prerequisites 49 | 50 | - Node.js (version 18 or higher) with ESM support 51 | 52 | ### Installation & Setup 53 | 54 | #### For Users 55 | 56 | Simply use npx as shown in the Quick Start section above. No installation or build required. 57 | 58 | #### For Contributors (Local Development) 59 | 60 | 1. Clone the repository 61 | 62 | 2. Install dependencies and build the MCP 63 | 64 | ```bash 65 | npm install 66 | npx nx build angular-mcp 67 | ``` 68 | 69 | 3. Locate the built server 70 | 71 | After building, the server will be available at `packages/angular-mcp/dist/main.js` 72 | 73 | ### MCP Configuration 74 | 75 | Add the server to your MCP client configuration (e.g., Claude Desktop, Cursor, Copilot, Windsurf or other MCP-compatible clients): 76 | 77 | #### For Users (npx - Recommended) 78 | 79 | ```json 80 | { 81 | "mcpServers": { 82 | "angular-toolkit": { 83 | "command": "npx", 84 | "args": [ 85 | "@push-based/angular-toolkit-mcp@latest", 86 | "--workspaceRoot=/absolute/path/to/your/angular/workspace", 87 | "--ds.uiRoot=relative/path/to/ui/components", 88 | "--ds.storybookDocsRoot=relative/path/to/storybook/docs", 89 | "--ds.deprecatedCssClassesPath=relative/path/to/component-options.mjs" 90 | ] 91 | } 92 | } 93 | } 94 | ``` 95 | 96 | #### For Contributors (Local Development) 97 | 98 | When developing locally, point to the built server: 99 | 100 | ```json 101 | { 102 | "mcpServers": { 103 | "angular-toolkit-mcp": { 104 | "command": "node", 105 | "args": [ 106 | "/absolute/path/to/angular-toolkit-mcp/packages/angular-mcp/dist/main.js", 107 | "--workspaceRoot=/absolute/path/to/your/angular/workspace", 108 | "--ds.uiRoot=relative/path/to/ui/components", 109 | "--ds.storybookDocsRoot=relative/path/to/storybook/docs", 110 | "--ds.deprecatedCssClassesPath=relative/path/to/component-options.mjs" 111 | ] 112 | } 113 | } 114 | } 115 | ``` 116 | 117 | > Note: `ds.storybookDocsRoot` and `ds.deprecatedCssClassesPath` are optional. The server will start without them. Tools that require these paths will return a clear error prompting you to provide the missing parameter. 118 | 119 | > **Note**: The example file contains configuration for `ESLint` official MCP which is required for the toolkit to work properly. 120 | 121 | ### Configuration Parameters 122 | 123 | #### Required Parameters 124 | 125 | | Parameter | Type | Description | Example | 126 | |-----------|------|-------------|---------| 127 | | `workspaceRoot` | Absolute path | Root directory of your Angular workspace | `/Users/dev/my-angular-app` | 128 | | `ds.uiRoot` | Relative path | Directory containing UI components | `packages/ui` | 129 | 130 | #### Optional Parameters 131 | 132 | | Parameter | Type | Description | Example | 133 | |-----------|------|-------------|---------| 134 | | `ds.storybookDocsRoot` | Relative path | Root directory containing Storybook documentation used by documentation-related tools | `storybook/docs` | 135 | | `ds.deprecatedCssClassesPath` | Relative path | JavaScript file mapping deprecated CSS classes used by violation and deprecated CSS tools | `design-system/component-options.mjs` | 136 | 137 | When optional parameters are omitted: 138 | 139 | - `ds.storybookDocsRoot`: Tools will skip Storybook documentation lookups (e.g., `get-ds-component-data` will still return implementation/import data but may have no docs files). 140 | - `ds.deprecatedCssClassesPath`: Tools that require the mapping will fail fast with a clear error. Affected tools include: `get-deprecated-css-classes`, `report-deprecated-css`, `report-all-violations`, and `report-violations`. 141 | 142 | #### Deprecated CSS Classes File Format 143 | 144 | The `component-options.mjs` file should export an array of component configurations: 145 | 146 | ```javascript 147 | const dsComponents = [ 148 | { 149 | componentName: 'DsButton', 150 | deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button'] 151 | }, 152 | { 153 | componentName: 'DsModal', 154 | deprecatedCssClasses: ['modal', 'old-modal'] 155 | } 156 | ]; 157 | 158 | export default dsComponents; 159 | ``` 160 | 161 | ### Example Project Structure 162 | 163 | ``` 164 | my-angular-workspace/ 165 | ├── packages/ 166 | │ ├── ui/ # ds.uiRoot 167 | │ │ ├── button/ 168 | │ │ ├── modal/ 169 | │ │ └── ... 170 | │ └── design-system/ 171 | │ └── component-options.mjs # ds.deprecatedCssClassesPath 172 | ├── storybook/ 173 | │ └── docs/ # ds.storybookDocsRoot 174 | └── apps/ 175 | └── my-app/ 176 | ``` 177 | 178 | ### Troubleshooting 179 | 180 | - **Server not starting**: Ensure all paths are correct and the server is built 181 | - **Permission errors**: Check that the Node.js process has read access to all specified directories 182 | - **Component not found**: Verify that component names in `component-options.mjs` match your actual component class names 183 | - **Path resolution issues**: Use absolute paths for `workspaceRoot` and relative paths (from workspace root) for other parameters 184 | 185 | ## Available Tools 186 | 187 | ### Component Analysis 188 | 189 | - **`report-violations`**: Report deprecated CSS usage in a directory with configurable grouping format 190 | 191 | - **`report-deprecated-css`**: Report deprecated CSS classes found in styling files 192 | 193 | - **`get-deprecated-css-classes`**: List deprecated CSS classes for a component 194 | 195 | ### Component Analysis 196 | 197 | - **`list-ds-components`**: List all available Design System components in the project with their file paths and metadata 198 | 199 | - **`get-ds-component-data`**: Return data for a component including implementation files, documentation files, and import path 200 | 201 | - **`build-component-usage-graph`**: Maps where given Angular components are imported (modules, specs, templates, styles) so refactors touch every file 202 | 203 | ### Tool behavior with optional parameters 204 | 205 | The following tools work without optional params: 206 | 207 | - `get-project-dependencies` 208 | - `build-component-usage-graph` 209 | - `get-ds-component-data` (documentation section is empty if `ds.storybookDocsRoot` is not set) 210 | - Component contract tools: 211 | - `build_component_contract` 212 | - `diff_component_contract` 213 | - `list_component_contracts` 214 | 215 | The following tools require optional params to work: 216 | 217 | - Requires `ds.deprecatedCssClassesPath`: 218 | - `get-deprecated-css-classes` 219 | - `report-deprecated-css` 220 | - `report-all-violations` 221 | - `report-violations` 222 | 223 | - Requires `ds.storybookDocsRoot` for docs lookup (skipped otherwise): 224 | - `get-ds-component-data` (docs files discovery only) 225 | 226 | ### Component Contracts 227 | 228 | - **`build_component_contract`**: Generate a static surface contract for a component's template and SCSS 229 | 230 | - **`diff_component_contract`**: Compare before/after contracts for parity and surface breaking changes 231 | 232 | - **`list_component_contracts`**: List all available component contracts in the .cursor/tmp/contracts directory 233 | 234 | ### Project Analysis 235 | 236 | - **`get-project-dependencies`**: Analyze project dependencies and detect if library is buildable/publishable. Checks for peer dependencies and validates import paths for components 237 | 238 | - **`lint-changes`**: Lint changed Angular files using ESLint rules. Automatically resolves ESLint config by walking up the directory tree 239 | 240 | ## Component Contract Workflow 241 | 242 | The component contract system provides a safety net for Angular component refactoring: 243 | 244 | 1. **Generate Initial Contract**: Create a baseline contract before refactoring 245 | 2. **Perform Refactoring**: Make your component changes 246 | 3. **Generate New Contract**: Create a contract after refactoring 247 | 4. **Compare Contracts**: Detect breaking changes and API differences 248 | 249 | ```bash 250 | # 1. Generate initial contract 251 | User: build_component_contract for my-component 252 | 253 | # 2. Make component changes... 254 | 255 | # 3. Generate new contract and compare 256 | User: build_component_contract for my-component 257 | User: diff_component_contract old-contract.json new-contract.json 258 | ``` 259 | 260 | ## Angular Project Integration 261 | 262 | This MCP server is designed for Angular project analysis and refactoring. It helps with: 263 | 264 | - **Migration Planning**: Identify all usages of deprecated components/classes 265 | - **Refactoring Safety**: Generate contracts to ensure no breaking changes 266 | - **Documentation Access**: Quick access to component documentation and examples 267 | - **Code Quality**: Analyze and improve code quality across your Angular project 268 | 269 | ## Documentation 270 | 271 | For comprehensive documentation, guides, and workflows, see our [Documentation Hub](docs/README.md). 272 | 273 | ## Contributing 274 | 275 | Please read our [Contributing Guide](CONTRIBUTING.md). 276 | 277 | ## License 278 | 279 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 280 | 281 | --- 282 | 283 | <div align="center"> 284 | <p><strong>Sponsored by</strong></p> 285 | <img src="assets/entain.png" alt="Entain" width="150"> 286 | </div> 287 | ``` -------------------------------------------------------------------------------- /CONTRIBUTING.MD: -------------------------------------------------------------------------------- ```markdown 1 | # Contributing to Angular Toolkit MCP 2 | 3 | Thank you for your interest in contributing to the Angular Toolkit MCP! This document provides guidelines and information for contributors. 4 | 5 | ## 📋 Table of Contents 6 | 7 | - [Getting Started](#getting-started) 8 | - [Development Setup](#development-setup) 9 | - [Project Structure](#project-structure) 10 | - [Development Workflow](#development-workflow) 11 | - [Testing](#testing) 12 | - [Code Quality](#code-quality) 13 | - [Submitting Changes](#submitting-changes) 14 | - [Documentation](#documentation) 15 | - [Debugging](#debugging) 16 | - [Release Process](#release-process) 17 | 18 | ## 🚀 Getting Started 19 | 20 | ### Prerequisites 21 | 22 | - **Node.js** (version 18 or higher) 23 | - **npm** (comes with Node.js) 24 | - **Git** for version control 25 | 26 | ### Fork and Clone 27 | 28 | 1. Fork the repository on GitHub 29 | 2. Clone your fork locally 30 | 31 | ## 🛠️ Development Setup 32 | 33 | ### Initial Setup 34 | 35 | 1. **Install dependencies:** 36 | ```bash 37 | npm install 38 | ``` 39 | 40 | 2. **Build the project:** 41 | ```bash 42 | npx nx build angular-toolkit-mcp 43 | ``` 44 | 45 | ### Nx Workspace Commands 46 | 47 | This project uses Nx for monorepo management. Key commands: 48 | 49 | ```bash 50 | # Build all projects 51 | npx nx run-many --target=build --all 52 | 53 | # Build specific project 54 | npx nx build angular-mcp-server 55 | 56 | # Run tests for all projects 57 | npx nx run-many --target=test --all 58 | 59 | # Lint all projects 60 | npx nx run-many --target=lint --all 61 | 62 | # Check project graph 63 | npx nx graph 64 | ``` 65 | 66 | ## 🏗️ Project Structure 67 | 68 | This is an Nx monorepo with the following structure: 69 | 70 | ``` 71 | ├── packages/ 72 | │ ├── angular-mcp/ # Main MCP client application 73 | │ ├── angular-mcp-server/ # Core MCP server library 74 | │ ├── minimal-repo/ # Test fixtures and examples 75 | │ └── shared/ # Shared libraries 76 | │ ├── angular-ast-utils/ # Angular AST parsing 77 | │ ├── ds-component-coverage/ # Design system analysis 78 | │ ├── models/ # Core types and schemas 79 | │ ├── styles-ast-utils/ # CSS/SCSS AST parsing 80 | │ ├── typescript-ast-utils/ # TypeScript AST utilities 81 | │ └── utils/ # General utilities 82 | ├── testing/ # Testing utilities and setup 83 | ├── docs/ # Documentation 84 | └── tools/ # Build and development tools 85 | ``` 86 | 87 | ### Key Projects 88 | 89 | - **`angular-mcp`**: Main executable MCP client 90 | - **`angular-mcp-server`**: Core server logic and MCP tools 91 | - **Shared libraries**: Reusable utilities for AST parsing, file operations, and Angular analysis 92 | 93 | ## 🔄 Development Workflow 94 | 95 | ### 1. Create a Feature Branch 96 | 97 | ```bash 98 | git checkout -b feature/your-feature-name 99 | ``` 100 | 101 | ### 2. Make Changes 102 | 103 | - Follow the existing code style and patterns 104 | - Add tests for new functionality 105 | - Update documentation as needed 106 | 107 | ### 3. Build and Test 108 | 109 | ```bash 110 | # Build affected projects 111 | npx nx affected --target=build 112 | 113 | # Run tests 114 | npx nx affected --target=test 115 | 116 | # Lint code 117 | npx nx affected --target=lint 118 | ``` 119 | 120 | ### 4. Commit Changes 121 | 122 | Follow conventional commit format: 123 | 124 | ```bash 125 | git commit -m "feat: add new MCP tool for component analysis" 126 | git commit -m "fix: resolve dependency resolution issue" 127 | git commit -m "docs: update API documentation" 128 | ``` 129 | 130 | ## 🧪 Testing 131 | 132 | ### Running Tests 133 | 134 | ```bash 135 | # Run all tests 136 | npx nx run-many --target=test --all 137 | 138 | # Run tests for specific project 139 | npx nx test angular-mcp-server 140 | 141 | # Run tests with coverage 142 | npx nx test angular-mcp-server --coverage 143 | ``` 144 | 145 | ### Writing Tests 146 | 147 | - Use Vitest for unit testing 148 | - Follow the existing test patterns 149 | - Mock external dependencies appropriately 150 | - Test both success and error scenarios 151 | 152 | ## 📏 Code Quality 153 | 154 | ### ESLint Configuration 155 | 156 | The project uses ESLint with TypeScript and Nx-specific rules: 157 | 158 | ```bash 159 | # Lint all files 160 | npx nx run-many --target=lint --all 161 | 162 | # Lint specific project 163 | npx nx lint angular-mcp-server 164 | 165 | # Auto-fix linting issues 166 | npx nx lint angular-mcp-server --fix 167 | ``` 168 | 169 | ### Code Style Guidelines 170 | 171 | - Use TypeScript strict mode 172 | - Follow functional programming patterns where possible 173 | - Use descriptive variable and function names 174 | - Add JSDoc comments for public APIs 175 | - Prefer composition over inheritance 176 | 177 | ### Pre-commit Checks 178 | 179 | Before committing, ensure: 180 | - [ ] All tests pass 181 | - [ ] No linting errors 182 | - [ ] Code builds successfully 183 | - [ ] Documentation is updated 184 | 185 | ## 📝 Submitting Changes 186 | 187 | ### Pull Request Process 188 | 189 | 1. **Push your branch:** 190 | ```bash 191 | git push origin feature/your-feature-name 192 | ``` 193 | 194 | 2. **Create a Pull Request:** 195 | - Use a descriptive title 196 | - Include a detailed description of changes 197 | - Reference any related issues 198 | - Add screenshots for UI changes 199 | 200 | 3. **PR Requirements:** 201 | - All CI checks must pass 202 | - Code review approval required 203 | - Documentation updates included 204 | - Tests added for new functionality 205 | 206 | ## 🐛 Debugging 207 | 208 | ### Debug Server 209 | 210 | Start the MCP server in debug mode: 211 | 212 | ```bash 213 | npx nx run angular-toolkit-mcp:debug 214 | ``` 215 | 216 | This starts the server with the MCP Inspector for debugging. 217 | 218 | 219 | ### Debugging Tips 220 | 221 | - Use the MCP Inspector for real-time debugging 222 | - Check server logs for detailed error information 223 | - Use `console.log` or debugger statements in development 224 | - Test with the minimal-repo examples 225 | 226 | ## 📦 Release Process 227 | 228 | ### Publishing to npm 229 | 230 | The Angular Toolkit MCP is published to npm as `@push-based/angular-toolkit-mcp`. Only maintainers with appropriate permissions can publish new versions. 231 | 232 | ### Release Steps 233 | 234 | 1. **Update Version** 235 | 236 | Update the version in `packages/angular-mcp/package.json` following semantic versioning: 237 | - **Patch** (0.1.0 → 0.1.1): Bug fixes 238 | - **Minor** (0.1.0 → 0.2.0): New features (backwards compatible) 239 | - **Major** (0.1.0 → 1.0.0): Breaking changes 240 | 241 | 2. **Build the Package** 242 | ```bash 243 | npx nx build angular-toolkit-mcp 244 | ``` 245 | 246 | 3. **Test the Package** 247 | ```bash 248 | cd packages/angular-mcp/dist 249 | npm pack 250 | # Test the generated .tgz file 251 | node main.js --help 252 | ``` 253 | 254 | 4. **Authenticate with npm** 255 | ```bash 256 | npm login 257 | ``` 258 | Ensure you have access to the `@push-based` scope. 259 | 260 | 5. **Publish to npm** 261 | ```bash 262 | npm run publish:mcp 263 | ``` 264 | Or manually: 265 | ```bash 266 | npx nx build angular-toolkit-mcp 267 | cd packages/angular-mcp/dist 268 | npm publish 269 | ``` 270 | 271 | 6. **Verify Publication** 272 | ```bash 273 | npm view @push-based/angular-toolkit-mcp 274 | npx @push-based/angular-toolkit-mcp@latest --help 275 | ``` 276 | 277 | 7. **Tag the Release** 278 | ```bash 279 | git tag v0.1.0 280 | git push origin v0.1.0 281 | ``` 282 | 283 | 8. **Update Documentation** 284 | - Update CHANGELOG.md with release notes 285 | - Update any version references in documentation 286 | 287 | ### Pre-release Checklist 288 | 289 | Before publishing a new version: 290 | - [ ] All tests pass (`npx nx run-many --target=test --all`) 291 | - [ ] No linting errors (`npx nx run-many --target=lint --all`) 292 | - [ ] Build succeeds (`npx nx build angular-toolkit-mcp`) 293 | - [ ] Version number updated in package.json 294 | - [ ] CHANGELOG.md updated with changes 295 | - [ ] Documentation updated as needed 296 | - [ ] Local npm pack test successful 297 | 298 | ## 📄 License 299 | 300 | By contributing, you agree that your contributions will be licensed under the MIT License. 301 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/storybook/card/card-tabs/overview.mdx: -------------------------------------------------------------------------------- ```markdown 1 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/multi-url-styl-inl-tmpl/multi-url-styl-inl-tmpl-1.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: red; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-inl-tmpl/url-styl-inl-tmpl.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: red; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-single-inl-tmpl/url-styl-single-inl-tmpl.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: red; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-url-tmpl/inl-styl-url-tmpl.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: red; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-style/url-styl-single.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: red; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-style/url-styl-span.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: blue; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/multi-url-styl-inl-tmpl/multi-url-styl-inl-tmpl-2.component.css: -------------------------------------------------------------------------------- ```css 1 | .btn-primary { 2 | color: blue; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-tmpl/url-tmpl-single.component.html: -------------------------------------------------------------------------------- ```html 1 | <button class="btn">click</button> 2 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-tmpl/url-tmpl-span.component.html: -------------------------------------------------------------------------------- ```html 1 | <button class="btn">click</button> 2 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-url-tmpl/inl-styl-url-tmpl.component.html: -------------------------------------------------------------------------------- ```html 1 | <button class="btn">Click me</button> 2 | ``` -------------------------------------------------------------------------------- /testing/utils/src/lib/constants.ts: -------------------------------------------------------------------------------- ```typescript 1 | export const MEMFS_VOLUME = '/memfs'; 2 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/inl-styl-url-tmpl/inl-styl-url-tmpl.component.html: -------------------------------------------------------------------------------- ```html 1 | <button [class]="'btn'">Click me</button> 2 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './lib/angular-mcp-server.js'; 2 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/src/lib/constants.ts: -------------------------------------------------------------------------------- ```typescript 1 | export const QUOTE_REGEX = /^['"`]+|['"`]+$/g; 2 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/styles.css: -------------------------------------------------------------------------------- ```css 1 | .btn { 2 | color: red; 3 | } 4 | 5 | .btn span { 6 | color: darkred; 7 | } 8 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/styles.scss: -------------------------------------------------------------------------------- ```scss 1 | .btn { 2 | color: red; 3 | span { 4 | color: darkred; 5 | } 6 | } 7 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/src/lib/constants.ts: -------------------------------------------------------------------------------- ```typescript 1 | export const ANGULAR_COMPONENT_DECORATOR = '@Component'; 2 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/src/lib/constants.ts: -------------------------------------------------------------------------------- ```typescript 1 | export const ANGULAR_DS_USAGE_PLUGIN_SLUG = 'ds-component-coverage'; 2 | ``` -------------------------------------------------------------------------------- /jest.preset.mjs: -------------------------------------------------------------------------------- ``` 1 | import nxPreset from '@nx/jest/preset'; 2 | 3 | export default { ...nxPreset }; 4 | ``` -------------------------------------------------------------------------------- /packages/shared/utils/src/lib/logging.ts: -------------------------------------------------------------------------------- ```typescript 1 | export const isVerbose = () => process.env['NG_MCP_VERBOSE'] === 'true'; 2 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/src/lib/styles-ast-utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | export function stylesAstUtils(): string { 2 | return 'styles-ast-utils'; 3 | } 4 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/app.routes.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Routes } from '@angular/router'; 2 | 3 | export const routes: Routes = []; 4 | ``` -------------------------------------------------------------------------------- /testing/setup/src/index.d.ts: -------------------------------------------------------------------------------- ```typescript 1 | export const EXCLUDED_FILES_TEST: string[]; 2 | export const MEMFS_VOLUME: string; 3 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/styles.css: -------------------------------------------------------------------------------- ```css 1 | /* You can add global styles to this file, and also import other style files */ 2 | ``` -------------------------------------------------------------------------------- /vitest.workspace.ts: -------------------------------------------------------------------------------- ```typescript 1 | export default [ 2 | '**/vite.config.{mjs,js,ts,mts}', 3 | '**/vitest.config.{mjs,js,ts,mts}', 4 | ]; 5 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export { 2 | createSharedVitestConfig, 3 | type SharedVitestConfigOptions, 4 | } from './lib/configuration'; 5 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/modal/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@frontend/ui/modal", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "peerDependencies": {} 6 | } 7 | ``` -------------------------------------------------------------------------------- /testing/setup/src/memfs.constants.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * Constants for memfs (in-memory file system) testing setup 3 | */ 4 | 5 | export const MEMFS_VOLUME = '/memfs'; 6 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/src/lib/schema.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { z } from 'zod'; 2 | 3 | export const AngularUnitSchema = z.enum([ 4 | 'component', 5 | 'pipe', 6 | 'directive', 7 | 'service', 8 | ]); 9 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/src/lib/postcss-safe-parser.d.ts: -------------------------------------------------------------------------------- ```typescript 1 | declare module 'postcss-safe-parser' { 2 | import { Parser } from 'postcss'; 3 | const safeParser: Parser; 4 | export default safeParser; 5 | } 6 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/tools.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolsConfig } from '@push-based/models'; 2 | import { dsTools } from './ds/tools.js'; 3 | 4 | export const TOOLS: ToolsConfig[] = [...dsTools] as const; 5 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/badge/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@frontend/ui/badge", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "peerDependencies": { 6 | "@angular/cdk": "19.2.9", 7 | "@angular/core": "19.2.7" 8 | } 9 | } 10 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './lib/constants.js'; 2 | export * from './lib/utils.js'; 3 | 4 | export { removeQuotes } from './lib/utils.js'; 5 | export { QUOTE_REGEX } from './lib/constants.js'; 6 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/rx-host-listener/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@frontend/ui/rx-host-listener", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "peerDependencies": { 6 | "@angular/core": "19.2.7", 7 | "rxjs": "^7.8.1" 8 | } 9 | } 10 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-tmpl/url-tmpl-span.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | templateUrl: './url-tmpl-span.component.html', 5 | selector: 'url-tmpl-span', 6 | }) 7 | export class UrlTmplSpanComponent {} 8 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-window.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-window', 5 | template: `<h3>Window usage</h3>`, 6 | }) 7 | export class BadWindowComponent { 8 | w = window; 9 | } 10 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/inl-tmpl-span.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | template: `<button class="btn">click</button>`, 5 | selector: 'inl-tmpl-span', 6 | }) 7 | export class InlStylSingleComponent {} 8 | ``` -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { Config } from 'jest'; 2 | import { getJestProjectsAsync } from '@nx/jest'; 3 | 4 | export default async (): Promise<Config> => ({ 5 | projects: await getJestProjectsAsync(), 6 | }); 7 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/inl-tmpl-single.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | template: '<button class="btn">click</button>', 5 | selector: 'inl-tmpl-single', 6 | }) 7 | export class InlTmplSingleComponent {} 8 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-tmpl/url-tmpl-single.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | templateUrl: './url-tmpl-single.component.html', 5 | selector: 'url-tmpl-single', 6 | }) 7 | export class UrlTmplSingleComponent {} 8 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/template-syntax/class-attribute.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'class-attribute', 5 | template: `<button class="btn">Click me</button>`, 6 | }) 7 | export class ClassAttributeComponent {} 8 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-document.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-document', 5 | template: `<h3>Document usage</h3>`, 6 | }) 7 | export class BadDocumentComponent { 8 | d = document; 9 | } 10 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/template-syntax/class-binding.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'class-binding', 5 | template: `<button [class.btn]>Click me</button>`, 6 | }) 7 | export class ClassAttributeUsageComponent {} 8 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-style/url-styl-span.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | styleUrls: ['url-styl-span.component.css'], 5 | selector: 'url-styl-span', 6 | template: '', 7 | }) 8 | export class UrlStylSpanComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/src/lib/styles-ast-utils.spec.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { stylesAstUtils } from './styles-ast-utils.js'; 2 | 3 | describe('stylesAstUtils', () => { 4 | it('should work', () => { 5 | expect(stylesAstUtils()).toEqual('styles-ast-utils'); 6 | }); 7 | }); 8 | ``` -------------------------------------------------------------------------------- /packages/shared/models/src/lib/diagnostics.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Issue } from '@code-pushup/models'; 2 | 3 | export interface DiagnosticsAware { 4 | // @TODO use Set<Issue & { code: number }> 5 | getIssues(): (Issue & { code?: number })[]; 6 | 7 | clear(): void; 8 | } 9 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/url-style/url-styl-single.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | styleUrls: ['url-styl-single.component.css'], 5 | selector: 'url-styl-single', 6 | template: '', 7 | }) 8 | export class UrlStylSingleComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-global-this.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-global-this', 5 | template: `<h3>Global this usage</h3>`, 6 | }) 7 | export class BadGlobalThisComponent { 8 | g = globalThis; 9 | } 10 | ``` -------------------------------------------------------------------------------- /packages/shared/models/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | } 9 | ], 10 | "nx": { 11 | "addTypecheckTarget": false 12 | } 13 | } 14 | ``` -------------------------------------------------------------------------------- /testing/setup/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | ``` -------------------------------------------------------------------------------- /testing/utils/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../angular-mcp-server" 8 | }, 9 | { 10 | "path": "./tsconfig.app.json" 11 | } 12 | ] 13 | } 14 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/url-css.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'url-css', 5 | template: ` <button class="btn">Click me</button>`, 6 | styleUrls: ['./styles.css'], 7 | }) 8 | export class UrlCssComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/url-scss.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'url-scss', 5 | template: ` <button class="btn">Click me</button>`, 6 | styleUrls: ['./styles.scss'], 7 | }) 8 | export class UrlScssComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './lib/styles-ast-utils.js'; 2 | export * from './lib/stylesheet.walk.js'; 3 | export * from './lib/utils.js'; 4 | export * from './lib/stylesheet.visitor.js'; 5 | export * from './lib/stylesheet.parse.js'; 6 | ``` -------------------------------------------------------------------------------- /testing/setup/src/index.mjs: -------------------------------------------------------------------------------- ``` 1 | export const EXCLUDED_FILES_TEST = [ 2 | 'mocks/**', 3 | '**/types.ts', 4 | '**/*.d.ts', 5 | '__snapshots__/**', 6 | '**/__tests__/**', 7 | '**/code-pushup.config.ts', 8 | '**/eslint*.config.js', 9 | '**/vitest*.config.mts', 10 | ]; 11 | ``` -------------------------------------------------------------------------------- /testing/utils/src/lib/string.ts: -------------------------------------------------------------------------------- ```typescript 1 | // removes all color codes from the output for snapshot readability 2 | export function removeColorCodes(stdout: string) { 3 | // eslint-disable-next-line no-control-regex 4 | return stdout.replace(/\u001B\[\d+m/g, ''); 5 | } 6 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/inl-styl-span.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | styles: [ 5 | ` 6 | .btn { 7 | color: red; 8 | } 9 | `, 10 | ], 11 | selector: 'inl-styl-span', 12 | template: '', 13 | }) 14 | export class InlStylSingleComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/inl-styl-single.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | styles: [ 5 | ` 6 | .btn { 7 | color: red; 8 | } 9 | `, 10 | ], 11 | selector: 'inl-styl-single', 12 | template: '', 13 | }) 14 | export class InlStylSingleComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/shared/models/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export type { CliArgsObject, ArgumentValue } from './lib/cli.js'; 2 | 3 | export type { 4 | ToolSchemaOptions, 5 | ToolsConfig, 6 | ToolHandlerContentResult, 7 | } from './lib/mcp.js'; 8 | export { type DiagnosticsAware } from './lib/diagnostics.js'; 9 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/badge/project.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "design-system-badge-ui", 3 | "$schema": "../../../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "packages/design-system/ui/badge/src", 6 | "tags": ["type:ui", "scope:shared"] 7 | } 8 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/modal/project.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "design-system-modal-ui", 3 | "$schema": "../../../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "packages/design-system/ui/modal/src", 6 | "tags": ["type:ui", "scope:shared"] 7 | } 8 | ``` -------------------------------------------------------------------------------- /packages/shared/models/src/lib/cli.ts: -------------------------------------------------------------------------------- ```typescript 1 | export type ArgumentValue = number | string | boolean | string[]; 2 | export type CliArgsObject<T extends object = Record<string, ArgumentValue>> = 3 | T extends never 4 | ? Record<string, ArgumentValue | undefined> | { _: string } 5 | : T; 6 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-url-tmpl/inl-styl-url-tmpl.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'inl-styl-url-tmpl', 5 | templateUrl: './inl-styl-url-tmpl.component.html', 6 | styleUrls: ['inl-styl-url-tmpl.component.css'], 7 | }) 8 | export class InlStylUrlTmplComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-inl-tmpl/url-styl-inl-tmpl.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'url-styl-inl-tmpl', 5 | template: `<button class="btn">Click me</button>`, 6 | styleUrls: ['./url-styl-inl-tmpl.component.css'], 7 | }) 8 | export class UrlStylInlTmplComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/inl-css.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'inl-css', 5 | template: ` <button class="btn">Click me</button>`, 6 | styles: [ 7 | ` 8 | .btn { 9 | color: red; 10 | } 11 | `, 12 | ], 13 | }) 14 | export class InlCssComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/url-styl-single-inl-tmpl/url-styl-inl-tmpl.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'url-styl-inl-tmpl', 5 | template: `<button class="btn">Click me</button>`, 6 | styleUrl: './url-styl-single-inl-tmpl.component.css', 7 | }) 8 | export class UrlStylInlTmplComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/component-contract/list/models/types.ts: -------------------------------------------------------------------------------- ```typescript 1 | /** 2 | * List Module Types 3 | * Types specific to listing and managing contract files 4 | */ 5 | 6 | export interface ContractFileInfo { 7 | fileName: string; 8 | filePath: string; 9 | componentName: string; 10 | timestamp: string; 11 | hash: string; 12 | size: string; 13 | } 14 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/sub-folder-1/button.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'ds-button', 5 | template: `<button class="ds-btn">Click me</button>`, 6 | styles: [ 7 | ` 8 | .ds-btn { 9 | color: red; 10 | } 11 | `, 12 | ], 13 | }) 14 | export class ButtonComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "nx": { 14 | "addTypecheckTarget": false 15 | } 16 | } 17 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "nx": { 14 | "addTypecheckTarget": false 15 | } 16 | } 17 | ``` -------------------------------------------------------------------------------- /testing/utils/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './lib/source-file-from.code.js'; 2 | export * from './lib/os-agnostic-paths.js'; 3 | export * from './lib/constants.js'; 4 | export * from './lib/e2e-setup.js'; 5 | export * from './lib/string.js'; 6 | export * from './lib/execute-process-helper.mock'; 7 | ``` -------------------------------------------------------------------------------- /testing/utils/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "include": ["vite.config.ts", "src/**/*.ts", "src/**/*.unit.test.ts"] 8 | } 9 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/main.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { bootstrapApplication } from '@angular/platform-browser'; 2 | import { appConfig } from './app/app.config'; 3 | import { AppComponent } from './app/app.component'; 4 | 5 | bootstrapApplication(AppComponent, appConfig).catch((err) => 6 | console.error(err) 7 | ); 8 | ``` -------------------------------------------------------------------------------- /packages/shared/utils/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './lib/utils.js'; 2 | export * from './lib/execute-process.js'; 3 | export * from './lib/logging.js'; 4 | export * from './lib/file/find-in-file.js'; 5 | export * from './lib/file/file.resolver.js'; 6 | export * from './lib/file/default-export-loader.js'; 7 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/storybook-host-app/src/components/segmented-control/segmented-control-tabs/examples.mdx: -------------------------------------------------------------------------------- ```markdown 1 | import { Canvas } from '@storybook/blocks'; 2 | 3 | import * as SegmentedControlStories from '../segmented-control.component.stories'; 4 | 5 | ## Default 6 | 7 | <Canvas of={SegmentedControlStories.Default} /> 8 | 9 | ## With Image 10 | 11 | <Canvas of={SegmentedControlStories.WithImage} /> 12 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/rx-host-listener/project.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "design-system-rx-host-listener-ui", 3 | "$schema": "../../../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "packages/design-system/ui/rx-host-listener/src", 6 | "tags": ["type:ui", "scope:shared"] 7 | } 8 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/mixed-external-assets.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'mixed-external-assets', 5 | templateUrl: './mixed-external-assets.component.html', 6 | styleUrls: ['./mixed-external-assets.component.css'], 7 | }) 8 | export class MixedExternalAssetsComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/template-syntax/ng-class-binding.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | import { NgClass } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'ng-class-binding', 6 | imports: [NgClass], 7 | template: `<button [ngClass]="'btn'">Click me</button>`, 8 | }) 9 | export class NgClassBindingComponent {} 10 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/segmented-control/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@frontend/ui/segmented-control", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "peerDependencies": { 6 | "@angular/cdk": "19.2.9", 7 | "@angular/common": "19.2.7", 8 | "@angular/core": "19.2.7", 9 | "@frontend/ui/rx-host-listener": "0.0.0" 10 | } 11 | } 12 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/segmented-control/project.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "design-system-segmented-control-ui", 3 | "$schema": "../../../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "packages/design-system/ui/segmented-control/src", 6 | "tags": ["type:ui", "scope:shared"] 7 | } 8 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/inl-styl-inl-tmpl/inl-styl-inl-tmpl.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'inl-styl-inl-tmpl', 5 | template: `<button class="btn">Click me</button>`, 6 | styles: [ 7 | ` 8 | .btn { 9 | color: red; 10 | } 11 | `, 12 | ], 13 | }) 14 | export class InlStylInlTmplComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/inl-styl-url-tmpl/inl-styl-url-tmpl.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'inl-styl-url-tmpl', 5 | templateUrl: './inl-styl-url-tmpl.component.html', 6 | styles: [ 7 | ` 8 | .btn { 9 | color: red; 10 | } 11 | `, 12 | ], 13 | }) 14 | export class InlStylUrlTmplComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/src/lib/template/template.walk.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { 2 | TmplAstNode, 3 | TmplAstVisitor, 4 | } from '@angular/compiler' with { 'resolution-mode': 'import' }; 5 | 6 | export function visitEachTmplChild( 7 | nodes: TmplAstNode[], 8 | visitor: TmplAstVisitor<unknown>, 9 | ) { 10 | nodes.forEach((node) => node.visit(visitor)); 11 | } 12 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/sub-folder-1/bad-alert.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-alert', 5 | template: `<div class="alert alert-danger">This is a legacy alert!</div>`, 6 | styles: [ 7 | ` 8 | .alert { 9 | color: red; 10 | } 11 | `, 12 | ], 13 | }) 14 | export class BadAlertComponent {} 15 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-mixed-external-assets.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-mixed-external-assets', 5 | templateUrl: './bad-mixed-external-assets.component.html', 6 | styleUrls: ['./bad-mixed-external-assets.component.css'], 7 | }) 8 | export class BadMixedExternalAssetsComponent {} 9 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-1/bad-mixed-external-assets-1.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-mixed-external-assets', 5 | templateUrl: './bad-mixed-external-assets-1.component.html', 6 | styleUrls: ['./bad-mixed-external-assets-1.component.css'], 7 | }) 8 | export class BadMixedExternalAssetsComponent1 {} 9 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-2/bad-mixed-external-assets-2.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-mixed-external-assets', 5 | templateUrl: './bad-mixed-external-assets-2.component.html', 6 | styleUrls: ['./bad-mixed-external-assets-2.component.css'], 7 | }) 8 | export class BadMixedExternalAssetsComponent2 {} 9 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-3/bad-mixed-external-assets-3.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-mixed-external-assets', 5 | templateUrl: './bad-mixed-external-assets-3.component.html', 6 | styleUrls: ['./bad-mixed-external-assets-3.component.css'], 7 | }) 8 | export class BadMixedExternalAssetsComponent3 {} 9 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/inl-scss.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'inl-scss', 5 | template: `<button class="btn">Click me</button>`, 6 | styles: [ 7 | ` 8 | .btn { 9 | span { 10 | color: darkred; 11 | } 12 | 13 | color: red; 14 | } 15 | `, 16 | ], 17 | }) 18 | export class InlCssComponent {} 19 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/eslint.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import tseslint from 'typescript-eslint'; 2 | import baseConfig from '../../eslint.config.mjs'; 3 | 4 | export default tseslint.config(...baseConfig, { 5 | files: ['**/*.ts'], 6 | languageOptions: { 7 | parserOptions: { 8 | projectService: true, 9 | tsconfigRootDir: import.meta.dirname, 10 | }, 11 | }, 12 | }); 13 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp/eslint.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import tseslint from 'typescript-eslint'; 2 | import baseConfig from '../../eslint.config.mjs'; 3 | 4 | export default tseslint.config(...baseConfig, { 5 | files: ['**/*.ts'], 6 | languageOptions: { 7 | parserOptions: { 8 | projectService: true, 9 | tsconfigRootDir: import.meta.dirname, 10 | }, 11 | }, 12 | }); 13 | ``` -------------------------------------------------------------------------------- /testing/setup/eslint.next.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import tseslint from 'typescript-eslint'; 2 | import baseConfig from '../../eslint.config.mjs'; 3 | 4 | export default tseslint.config(...baseConfig, { 5 | files: ['**/*.ts'], 6 | languageOptions: { 7 | parserOptions: { 8 | projectService: true, 9 | tsconfigRootDir: import.meta.dirname, 10 | }, 11 | }, 12 | }); 13 | ``` -------------------------------------------------------------------------------- /testing/utils/eslint.next.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import tseslint from 'typescript-eslint'; 2 | import baseConfig from '../../eslint.config.mjs'; 3 | 4 | export default tseslint.config(...baseConfig, { 5 | files: ['**/*.ts'], 6 | languageOptions: { 7 | parserOptions: { 8 | projectService: true, 9 | tsconfigRootDir: import.meta.dirname, 10 | }, 11 | }, 12 | }); 13 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/eslint.next.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import tseslint from 'typescript-eslint'; 2 | import baseConfig from '../../eslint.config.mjs'; 3 | 4 | export default tseslint.config(...baseConfig, { 5 | files: ['**/*.ts'], 6 | languageOptions: { 7 | parserOptions: { 8 | projectService: true, 9 | tsconfigRootDir: import.meta.dirname, 10 | }, 11 | }, 12 | }); 13 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/eslint.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import tseslint from 'typescript-eslint'; 2 | import baseConfig from '../../../eslint.config.mjs'; 3 | 4 | export default tseslint.config(...baseConfig, { 5 | files: ['**/*.ts'], 6 | languageOptions: { 7 | parserOptions: { 8 | projectService: true, 9 | tsconfigRootDir: import.meta.dirname, 10 | }, 11 | }, 12 | }); 13 | ``` -------------------------------------------------------------------------------- /testing/setup/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "include": [ 8 | "vite.config.ts", 9 | "vitest.integration.config.mts", 10 | "src/**/*.ts", 11 | "src/**/*.unit.test.ts" 12 | ] 13 | } 14 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/shared/models/input-schemas.model.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolSchemaOptions } from '@push-based/models'; 2 | 3 | export const componentInputSchema = ( 4 | description: string, 5 | ): ToolSchemaOptions['inputSchema'] => ({ 6 | type: 'object', 7 | properties: { 8 | componentName: { 9 | type: 'string', 10 | description, 11 | }, 12 | }, 13 | required: ['componentName'], 14 | }); 15 | ``` -------------------------------------------------------------------------------- /testing/setup/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/testing-setup", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "main": "./src/index.mjs", 6 | "types": "./src/index.d.ts", 7 | "private": true, 8 | "nx": { 9 | "sourceRoot": "testing/setup/src", 10 | "projectType": "library", 11 | "name": "testing-setup" 12 | }, 13 | "module": "./src/index.mjs" 14 | } 15 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/multi-url-styl-inl-tmpl/multi-url-styl-inl-tmpl.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'multi-url-styl-inl-tmpl', 5 | template: `<button class="">Click me</button>`, 6 | styleUrls: [ 7 | './multi-url-styl-inl-tmpl-1.component.css', 8 | './multi-url-styl-inl-tmpl-2.component.css', 9 | ], 10 | }) 11 | export class MultiUrlStylInlTmplComponent {} 12 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/shared/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './violation-analysis/index.js'; 2 | export * from './utils/regex-helpers.js'; 3 | export * from './utils/handler-helpers.js'; 4 | export * from './utils/component-validation.js'; 5 | export * from './utils/output.utils.js'; 6 | export * from './utils/cross-platform-path.js'; 7 | export * from './models/schema-helpers.js'; 8 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-alert.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-alert', 5 | styles: [ 6 | ` 7 | .alert { 8 | padding: 10px; 9 | } 10 | .btn { 11 | padding: 10px; 12 | } 13 | `, 14 | ], 15 | template: `<div class="alert alert-danger">This is a legacy alert!</div>`, 16 | }) 17 | export class BadAlertComponent {} 18 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/index.html: -------------------------------------------------------------------------------- ```html 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | <head> 4 | <meta charset="utf-8" /> 5 | <title>Minimal</title> 6 | <base href="/" /> 7 | <meta name="viewport" content="width=device-width, initial-scale=1" /> 8 | <link rel="icon" type="image/x-icon" href="favicon.ico" /> 9 | </head> 10 | <body> 11 | <app-root></app-root> 12 | </body> 13 | </html> 14 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { 2 | CallToolRequest, 3 | CallToolResult, 4 | } from '@modelcontextprotocol/sdk/types.js'; 5 | 6 | export function toolNotFound(request: CallToolRequest): CallToolResult { 7 | return { 8 | content: [ 9 | { 10 | type: 'text', 11 | text: `Tool not found: ${request.params.name}`, 12 | isError: true, 13 | }, 14 | ], 15 | }; 16 | } 17 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/bad-button-dropdown.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-button-dropdown', 5 | template: ` 6 | <button class="btn btn-primary">Click Me</button> 7 | <select class="dropdown"> 8 | <option>Option 1</option> 9 | <option>Option 2</option> 10 | </select> 11 | `, 12 | }) 13 | export class BadButtonDropdownComponent {} 14 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/app.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; 2 | import { provideRouter } from '@angular/router'; 3 | 4 | import { routes } from './app.routes'; 5 | 6 | export const appConfig: ApplicationConfig = { 7 | providers: [ 8 | provideZoneChangeDetection({ eventCoalescing: true }), 9 | provideRouter(routes), 10 | ], 11 | }; 12 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-mixed.module.ts: -------------------------------------------------------------------------------- ```typescript 1 | // generate angular module 2 | 3 | import { NgModule } from '@angular/core'; 4 | import { MixedStylesNotStandaloneComponent } from './bad-mixed-not-standalone.component'; 5 | 6 | @NgModule({ 7 | declarations: [], 8 | imports: [MixedStylesNotStandaloneComponent], 9 | exports: [MixedStylesNotStandaloneComponent], 10 | }) 11 | export class BadModuleModule {} 12 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/component-usage-graph/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export { buildComponentUsageGraph } from './utils/component-usage-graph-builder.js'; 2 | export { buildComponentUsageGraphTools } from './build-component-usage-graph.tool.js'; 3 | 4 | export type { 5 | ComponentUsageGraphResult, 6 | BuildComponentUsageGraphOptions, 7 | FileInfo, 8 | DependencyInfo, 9 | ComponentMetadata, 10 | } from './models/types.js'; 11 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-1/bad-mixed-1.module.ts: -------------------------------------------------------------------------------- ```typescript 1 | // generate angular module 2 | 3 | import { NgModule } from '@angular/core'; 4 | import { MixedStylesNotStandaloneComponent1 } from './bad-mixed-not-standalone-1.component'; 5 | 6 | @NgModule({ 7 | declarations: [], 8 | imports: [MixedStylesNotStandaloneComponent1], 9 | exports: [MixedStylesNotStandaloneComponent1], 10 | }) 11 | export class BadModuleModule1 {} 12 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-2/bad-mixed-2.module.ts: -------------------------------------------------------------------------------- ```typescript 1 | // generate angular module 2 | 3 | import { NgModule } from '@angular/core'; 4 | import { MixedStylesNotStandaloneComponent2 } from './bad-mixed-not-standalone-2.component'; 5 | 6 | @NgModule({ 7 | declarations: [], 8 | imports: [MixedStylesNotStandaloneComponent2], 9 | exports: [MixedStylesNotStandaloneComponent2], 10 | }) 11 | export class BadModuleModule2 {} 12 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-3/bad-mixed-3.module.ts: -------------------------------------------------------------------------------- ```typescript 1 | // generate angular module 2 | 3 | import { NgModule } from '@angular/core'; 4 | import { MixedStylesNotStandaloneComponent3 } from './bad-mixed-not-standalone-3.component'; 5 | 6 | @NgModule({ 7 | declarations: [MixedStylesNotStandaloneComponent3], 8 | imports: [], 9 | exports: [MixedStylesNotStandaloneComponent3], 10 | }) 11 | export class BadModuleModule3 {} 12 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "references": [ 8 | { 9 | "path": "../../../testing/setup/tsconfig.json" 10 | } 11 | ], 12 | "include": ["vite.config.ts", "src/**/*.ts", "src/**/*.unit.test.ts"] 13 | } 14 | ``` -------------------------------------------------------------------------------- /packages/shared/utils/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../../../testing/vitest-setup" 8 | }, 9 | { 10 | "path": "../models" 11 | }, 12 | { 13 | "path": "./tsconfig.lib.json" 14 | }, 15 | { 16 | "path": "./tsconfig.spec.json" 17 | } 18 | ], 19 | "nx": { 20 | "addTypecheckTarget": false 21 | } 22 | } 23 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-alert-tooltip-input.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-alert-tooltip-input', 5 | template: ` 6 | <div class="alert alert-tooltip">This is a warning alert!</div> 7 | 8 | <div class="tooltip">Hover over me!</div> 9 | 10 | <input class="form-control" placeholder="Enter text here" /> 11 | `, 12 | }) 13 | export class BadAlertTooltipInputComponent {} 14 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/sub-folder-1/sub-folder-2/bad-alert-tooltip-input.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-alert-tooltip-input', 5 | template: ` 6 | <div class="alert alert-warning">This is a warning alert!</div> 7 | 8 | <div class="tooltip">Hover over me!</div> 9 | 10 | <input class="form-control" placeholder="Enter text here" /> 11 | `, 12 | }) 13 | export class BadAlertTooltipInputComponent {} 14 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export * from './lib/parse-component.js'; 2 | export * from './lib/constants.js'; 3 | export * from './lib/template/utils.js'; 4 | export * from './lib/template/template.walk.js'; 5 | export * from './lib/template/noop-tmpl-visitor.js'; 6 | export * from './lib/styles/utils.js'; 7 | export * from './lib/utils.js'; 8 | export * from './lib/types.js'; 9 | export * from './lib/schema.js'; 10 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/modal/src/modal-content.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { 2 | ChangeDetectionStrategy, 3 | Component, 4 | ViewEncapsulation, 5 | } from '@angular/core'; 6 | 7 | @Component({ 8 | selector: 'ds-modal-content', 9 | template: `<ng-content />`, 10 | host: { 11 | class: 'ds-modal-content', 12 | }, 13 | standalone: true, 14 | encapsulation: ViewEncapsulation.None, 15 | changeDetection: ChangeDetectionStrategy.OnPush, 16 | }) 17 | export class DsModalContent {} 18 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/jest", 5 | "types": ["jest", "node"], 6 | "forceConsistentCasingInFileNames": true 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | } 18 | ] 19 | } 20 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/jest", 5 | "types": ["jest", "node"], 6 | "forceConsistentCasingInFileNames": true 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | } 18 | ] 19 | } 20 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/jest", 5 | "types": ["jest", "node"], 6 | "forceConsistentCasingInFileNames": true 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | } 18 | ] 19 | } 20 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/jest", 5 | "types": ["jest", "node"], 6 | "forceConsistentCasingInFileNames": true 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | } 18 | ] 19 | } 20 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/report-violations/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | export { reportViolationsTools } from './report-violations.tool.js'; 2 | export { reportAllViolationsTools } from './report-all-violations.tool.js'; 3 | 4 | export type { 5 | ReportViolationsOptions, 6 | ViolationResult, 7 | ViolationIssue, 8 | ViolationAudit, 9 | FileViolation, 10 | FileViolationGroup, 11 | FileViolationGroups, 12 | FolderViolationSummary, 13 | FolderViolationGroups, 14 | } from './models/types.js'; 15 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../models" 8 | }, 9 | { 10 | "path": "../styles-ast-utils" 11 | }, 12 | { 13 | "path": "../angular-ast-utils" 14 | }, 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ], 22 | "nx": { 23 | "addTypecheckTarget": false 24 | } 25 | } 26 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../typescript-ast-utils" 8 | }, 9 | { 10 | "path": "../utils" 11 | }, 12 | { 13 | "path": "../styles-ast-utils" 14 | }, 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ], 22 | "nx": { 23 | "addTypecheckTarget": false 24 | } 25 | } 26 | ``` -------------------------------------------------------------------------------- /testing/utils/src/lib/source-file-from.code.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Project } from 'ts-morph'; 2 | import type { SourceFile as TsSourceFile } from 'typescript'; 3 | 4 | export const sourceFileFromCode = ({ 5 | path, 6 | code, 7 | }: { 8 | path?: string; 9 | code: string; 10 | }) => { 11 | const project = new Project({ useInMemoryFileSystem: true }); 12 | const tsMorphSourceFile = project.createSourceFile(path ?? 'cmp.ts', code); 13 | return tsMorphSourceFile as unknown as TsSourceFile; 14 | }; 15 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp/tsconfig.app.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "types": ["node", "express"], 6 | "rootDir": "src", 7 | "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo", 8 | "module": "NodeNext", 9 | "moduleResolution": "NodeNext" 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": [], 13 | "references": [ 14 | { 15 | "path": "../angular-mcp-server/tsconfig.lib.json" 16 | } 17 | ] 18 | } 19 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-modal-progress.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-modal-progress', 5 | template: ` 6 | <div class="modal"> 7 | <div class="modal-content"> 8 | <h2>Legacy Modal</h2> 9 | <p>This is an old modal.</p> 10 | </div> 11 | </div> 12 | 13 | <div class="progress-bar"> 14 | <div class="progress" style="width: 50%;"></div> 15 | </div> 16 | `, 17 | }) 18 | export class BadModalProgressComponent {} 19 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/src/bad-modal-progress.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-modal-progress', 5 | template: ` 6 | <div class="modal"> 7 | <div class="modal-content"> 8 | <h2>Legacy Modal</h2> 9 | <p>This is an old modal.</p> 10 | </div> 11 | </div> 12 | 13 | <div class="progress-bar"> 14 | <div class="progress" style="width: 50%;"></div> 15 | </div> 16 | `, 17 | }) 18 | export class BadModalProgressComponent {} 19 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/tsconfig.app.json: -------------------------------------------------------------------------------- ```json 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "./out-tsc/app", 7 | "types": [] 8 | }, 9 | "files": ["src/main.ts"], 10 | "include": ["src/**/*.d.ts"] 11 | } 12 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "./out-tsc/spec", 7 | "types": ["jasmine"] 8 | }, 9 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] 10 | } 11 | ``` -------------------------------------------------------------------------------- /tools/nx-advanced-profile.postinstall.js: -------------------------------------------------------------------------------- ```javascript 1 | import { writeFileSync } from 'node:fs'; 2 | import { readFileSync } from 'node:fs'; 3 | 4 | // This is adding `import("./../../../../tools/perf_hooks.patch");` to your `node_modules/nx/src/utils/perf-logging.js`. 5 | writeFileSync( 6 | './node_modules/nx/src/utils/perf-logging.js', 7 | readFileSync( 8 | './node_modules/nx/src/utils/perf-logging.js', 9 | 'utf-8', 10 | ).toString() + 'import("./../../../../tools/perf_hooks.patch");', 11 | ); 12 | ``` -------------------------------------------------------------------------------- /testing/setup/eslint.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import nextEslintConfig from './eslint.next.config.mjs'; 2 | 3 | // 🚨 DO NOT EDIT THIS FILE MANUALLY! 🚨 4 | // Run `pnpm eslint-next/nx` to update or remove this file if all rules pass. 5 | // Add new rules globally to the `eslint.config.js` or locally to the `eslint.next.config.js` file. 6 | // For details, refer to: tools/scripts/eslint-next/README.md 7 | export default [ 8 | ...nextEslintConfig, 9 | { 10 | files: ['**/*'], 11 | rules: {}, 12 | }, 13 | ]; 14 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-button-dropdown.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-bad-button-dropdown', 5 | styles: [ 6 | ` 7 | .btn { 8 | margin: 10px; 9 | } 10 | .btn-dropdown { 11 | padding: 10px; 12 | } 13 | `, 14 | ], 15 | template: ` 16 | <button class="btn btn-primary">Click Me</button> 17 | <select class="btn-dropdown"> 18 | <option>Option 1</option> 19 | <option>Option 2</option> 20 | </select> 21 | `, 22 | }) 23 | export class BadButtonDropdownComponent {} 24 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "../shared/ds-component-coverage" 8 | }, 9 | { 10 | "path": "../shared/styles-ast-utils" 11 | }, 12 | { 13 | "path": "../shared/angular-ast-utils" 14 | }, 15 | { 16 | "path": "../shared/utils" 17 | }, 18 | { 19 | "path": "../shared/models" 20 | }, 21 | { 22 | "path": "./tsconfig.lib.json" 23 | } 24 | ], 25 | "nx": { 26 | "addTypecheckTarget": false 27 | } 28 | } 29 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/standalone-module-conflict.module.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { StandaloneModuleConflictComponent } from './standalone-module-conflict.component'; 4 | 5 | @NgModule({ 6 | declarations: [ 7 | StandaloneModuleConflictComponent // ERROR: Standalone components should not be declared in modules 8 | ], 9 | imports: [ 10 | CommonModule 11 | ], 12 | exports: [ 13 | StandaloneModuleConflictComponent 14 | ] 15 | }) 16 | export class StandaloneModuleConflictModule { } ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/typescript-ast-utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | "./package.json": "./package.json", 11 | ".": { 12 | "development": "./src/index.ts", 13 | "types": "./dist/index.d.ts", 14 | "import": "./dist/index.js", 15 | "default": "./dist/index.js" 16 | } 17 | }, 18 | "nx": { 19 | "name": "typescript-ast-utils" 20 | } 21 | } 22 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/bad-this-window-document.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component, inject, InjectionToken } from '@angular/core'; 2 | import { DOCUMENT } from '@angular/common'; 3 | 4 | export const WINDOW = new InjectionToken<any>('Safe access window object', { 5 | providedIn: 'root', 6 | factory: () => inject(DOCUMENT).defaultView, 7 | }); 8 | 9 | @Component({ 10 | selector: 'app-bad-this-window-document', 11 | template: `<h3>Window usage</h3>`, 12 | }) 13 | export class BadThisWindowDocumentComponent { 14 | readonly #window = inject(WINDOW); 15 | 16 | doc = this.#window.document; 17 | } 18 | ``` -------------------------------------------------------------------------------- /packages/shared/models/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "baseUrl": ".", 7 | "rootDir": "src", 8 | "outDir": "dist", 9 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 10 | "emitDeclarationOnly": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "types": ["node"] 13 | }, 14 | "include": ["src/**/*.ts"], 15 | "references": [], 16 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 17 | } 18 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "baseUrl": ".", 7 | "rootDir": "src", 8 | "outDir": "dist", 9 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 10 | "emitDeclarationOnly": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "types": ["node"] 13 | }, 14 | "include": ["src/**/*.ts"], 15 | "references": [], 16 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 17 | } 18 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "baseUrl": ".", 7 | "rootDir": "src", 8 | "outDir": "dist", 9 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 10 | "emitDeclarationOnly": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "types": ["node"] 13 | }, 14 | "include": ["src/**/*.ts"], 15 | "references": [], 16 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 17 | } 18 | ``` -------------------------------------------------------------------------------- /packages/shared/utils/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | "./package.json": "./package.json", 11 | ".": { 12 | "development": "./src/index.ts", 13 | "types": "./dist/index.d.ts", 14 | "import": "./dist/index.js", 15 | "default": "./dist/index.js" 16 | } 17 | }, 18 | "nx": { 19 | "tags": [ 20 | "scope:shared", 21 | "type:lib" 22 | ] 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "declarationMap": true, 5 | "emitDeclarationOnly": true, 6 | "importHelpers": true, 7 | "isolatedModules": true, 8 | "lib": ["es2022"], 9 | "module": "NodeNext", 10 | "moduleResolution": "NodeNext", 11 | "noEmitOnError": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "noImplicitOverride": true, 14 | "noImplicitReturns": true, 15 | "noUnusedLocals": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "es2022" 19 | } 20 | } 21 | ``` -------------------------------------------------------------------------------- /packages/shared/models/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/models", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | "./package.json": "./package.json", 11 | ".": { 12 | "development": "./src/index.ts", 13 | "types": "./dist/index.d.ts", 14 | "import": "./dist/index.js", 15 | "default": "./dist/index.js" 16 | } 17 | }, 18 | "nx": { 19 | "tags": [ 20 | "scope:shared", 21 | "type:lib" 22 | ] 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /packages/shared/models/src/lib/mcp.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { CallToolResult, ToolSchema } from '@modelcontextprotocol/sdk/types.js'; 2 | import { z } from 'zod'; 3 | import { 4 | CallToolResultSchema, 5 | CallToolRequest, 6 | } from '@modelcontextprotocol/sdk/types.js'; 7 | 8 | export type ToolSchemaOptions = z.infer<typeof ToolSchema>; 9 | export type ToolHandlerContentResult = z.infer< 10 | typeof CallToolResultSchema 11 | >['content'][number]; 12 | 13 | export type ToolsConfig = { 14 | schema: ToolSchemaOptions; 15 | handler: (o: CallToolRequest) => Promise<CallToolResult>; 16 | }; 17 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/src/lib/stylesheet.parse.ts: -------------------------------------------------------------------------------- ```typescript 1 | import postcss from 'postcss'; 2 | import safeParser from 'postcss-safe-parser'; 3 | 4 | /** 5 | * Parse a stylesheet content and return the AST. 6 | * PostCss is indexed with 1, so we don't need to adjust the line number to be linkable. 7 | * 8 | * @param content 9 | * @param filePath 10 | */ 11 | export function parseStylesheet(content: string, filePath: string) { 12 | return postcss().process(content, { 13 | parser: safeParser, 14 | from: filePath, 15 | map: { 16 | inline: false, // preserve line number 17 | }, 18 | }); 19 | } 20 | ``` -------------------------------------------------------------------------------- /testing/utils/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/testing-utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.js", 7 | "types": "./dist/index.d.ts", 8 | "typings": "./dist/index.d.ts", 9 | "exports": { 10 | "./package.json": "./package.json", 11 | ".": { 12 | "types": "./dist/index.d.ts", 13 | "import": "./dist/index.js" 14 | } 15 | }, 16 | "nx": { 17 | "sourceRoot": "testing/utils/src", 18 | "projectType": "library", 19 | "name": "testing-utils", 20 | "targets": {} 21 | } 22 | } 23 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/testing-vitest-setup", 3 | "version": "0.0.1", 4 | "main": "./dist/index.js", 5 | "typings": "./dist/index.d.ts", 6 | "private": true, 7 | "nx": { 8 | "sourceRoot": "testing/vitest-setup/src", 9 | "projectType": "library", 10 | "name": "testing-vitest-setup" 11 | }, 12 | "exports": { 13 | "./package.json": "./package.json", 14 | ".": { 15 | "types": "./dist/index.d.ts", 16 | "import": "./dist/index.js" 17 | } 18 | }, 19 | "types": "./dist/index.d.ts", 20 | "module": "./dist/index.js" 21 | } 22 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/styles-ast-utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | "./package.json": "./package.json", 11 | ".": { 12 | "development": "./src/index.ts", 13 | "types": "./dist/index.d.ts", 14 | "import": "./dist/index.js", 15 | "default": "./dist/index.js" 16 | } 17 | }, 18 | "nx": { 19 | "tags": [ 20 | "scope:shared", 21 | "type:lib" 22 | ] 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/angular-ast-utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | "./package.json": "./package.json", 11 | ".": { 12 | "development": "./src/index.ts", 13 | "types": "./dist/index.d.ts", 14 | "import": "./dist/index.js", 15 | "default": "./dist/index.js" 16 | } 17 | }, 18 | "nx": { 19 | "tags": [ 20 | "scope:shared", 21 | "type:lib" 22 | ] 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/standalone-module-conflict.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-standalone-module-conflict', 5 | standalone: true, 6 | template: ` 7 | <div> 8 | <h2>Standalone Module Conflict Test</h2> 9 | <p>This standalone component should NOT be declared in a module</p> 10 | </div> 11 | `, 12 | styles: [` 13 | div { 14 | background: #ffe6e6; 15 | padding: 15px; 16 | border: 1px solid red; 17 | } 18 | `] 19 | }) 20 | export class StandaloneModuleConflictComponent { 21 | title = 'Standalone Component in Module'; 22 | } ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/component-usage-graph/utils/angular-parser.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { parseComponents } from '@push-based/angular-ast-utils'; 2 | import { ComponentMetadata } from '../models/types.js'; 3 | 4 | export async function parseAngularComponent( 5 | filePath: string, 6 | ): Promise<ComponentMetadata | null> { 7 | try { 8 | const [component] = await parseComponents([filePath]); 9 | return component ? { className: component.className } : null; 10 | } catch (ctx) { 11 | throw new Error( 12 | `Failed to parse Angular component from ${filePath}: ${(ctx as Error).message}`, 13 | ); 14 | } 15 | } 16 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/shared/utils/output.utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; 2 | 3 | export const buildText = ( 4 | text: string, 5 | isError = false, 6 | ): CallToolResult['content'][0] => { 7 | return { 8 | type: 'text', 9 | text, 10 | isError, 11 | }; 12 | }; 13 | 14 | export const buildTextResponse = (texts: string[]): CallToolResult => { 15 | return { 16 | content: [...texts.map((text) => buildText(text, false))], 17 | }; 18 | }; 19 | 20 | export const throwError = (text: string): CallToolResult => { 21 | return { 22 | content: [buildText(text, true)], 23 | }; 24 | }; 25 | ``` -------------------------------------------------------------------------------- /testing/utils/eslint.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import nextEslintConfig from './eslint.next.config.mjs'; 2 | 3 | // 🚨 DO NOT EDIT THIS FILE MANUALLY! 🚨 4 | // Run `pnpm eslint-next/nx` to update or remove this file if all rules pass. 5 | // Add new rules globally to the `eslint.config.js` or locally to the `eslint.next.config.js` file. 6 | // For details, refer to: tools/scripts/eslint-next/README.md 7 | export default [ 8 | ...nextEslintConfig, 9 | { 10 | files: ['**/*'], 11 | rules: { 12 | // ❌ Errors: 1 13 | '@nx/dependency-checks': 'off', // ❌ 1 error 🛠️ 14 | }, 15 | }, 16 | ]; 17 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/eslint.config.mjs: -------------------------------------------------------------------------------- ``` 1 | import nextEslintConfig from './eslint.next.config.mjs'; 2 | 3 | // 🚨 DO NOT EDIT THIS FILE MANUALLY! 🚨 4 | // Run `pnpm eslint-next/nx` to update or remove this file if all rules pass. 5 | // Add new rules globally to the `eslint.config.js` or locally to the `eslint.next.config.js` file. 6 | // For details, refer to: tools/scripts/eslint-next/README.md 7 | export default [ 8 | ...nextEslintConfig, 9 | { 10 | files: ['**/*'], 11 | rules: { 12 | // ❌ Errors: 1 13 | '@nx/dependency-checks': 'off', // ❌ 1 error 🛠️ 14 | }, 15 | }, 16 | ]; 17 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/storybook-host-app/src/components/badge/badge.component.mdx: -------------------------------------------------------------------------------- ```markdown 1 | import { Meta } from '@storybook/blocks'; 2 | 3 | import * as BadgeStories from './badge.component.stories'; 4 | import OverviewTab from './badge-tabs/overview.mdx'; 5 | import ExamplesTab from './badge-tabs/examples.mdx'; 6 | import ApiTab from './badge-tabs/api.mdx'; 7 | import { ComponentDocTabs } from '../../../../shared-storybook-utils/src/lib/component-doc-tabs/component-doc-tabs.mdx'; 8 | 9 | <Meta of={BadgeStories} /> 10 | 11 | # Badge Component 12 | 13 | <ComponentDocTabs 14 | OverviewTab={OverviewTab} 15 | ExamplesTab={ExamplesTab} 16 | ApiTab={ApiTab} 17 | /> 18 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/storybook-host-app/src/components/modal/modal.component.mdx: -------------------------------------------------------------------------------- ```markdown 1 | import { Meta } from '@storybook/blocks'; 2 | 3 | import * as ModalStories from './modal.component.stories'; 4 | import OverviewTab from './modal-tabs/overview.mdx'; 5 | import ExamplesTab from './modal-tabs/examples.mdx'; 6 | import ApiTab from './modal-tabs/api.mdx'; 7 | import { ComponentDocTabs } from '../../../../shared-storybook-utils/src/lib/component-doc-tabs/component-doc-tabs.mdx'; 8 | 9 | <Meta of={ModalStories} /> 10 | 11 | # Modal Component 12 | 13 | <ComponentDocTabs 14 | OverviewTab={OverviewTab} 15 | ExamplesTab={ExamplesTab} 16 | ApiTab={ApiTab} 17 | /> 18 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/modal/src/modal-header-drag/modal-header-drag.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { 2 | ChangeDetectionStrategy, 3 | Component, 4 | ViewEncapsulation, 5 | } from '@angular/core'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'ds-modal-header-drag', 10 | host: { 11 | class: 'ds-modal-header-drag', 12 | role: 'dialog', 13 | 'aria-label': 'Modal header drag dialog', 14 | }, 15 | template: `<span class="ds-modal-header-drag-rectangle"></span>`, 16 | styleUrl: 'modal-header-drag.component.scss', 17 | changeDetection: ChangeDetectionStrategy.OnPush, 18 | encapsulation: ViewEncapsulation.None, 19 | }) 20 | export class DsModalHeaderDrag {} 21 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@push-based/angular-mcp-server", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "scripts": { 10 | "debug": "nx run angular-mcp:debug" 11 | }, 12 | "exports": { 13 | "./package.json": "./package.json", 14 | ".": { 15 | "development": "./src/index.ts", 16 | "types": "./dist/index.d.ts", 17 | "import": "./dist/index.js", 18 | "default": "./dist/index.js" 19 | } 20 | }, 21 | "nx": { 22 | "name": "angular-mcp-server" 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /packages/angular-mcp-server/src/lib/tools/ds/component-contract/list/models/schema.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ToolSchemaOptions } from '@push-based/models'; 2 | import { 3 | createProjectAnalysisSchema, 4 | COMMON_ANNOTATIONS, 5 | } from '../../../shared/models/schema-helpers.js'; 6 | 7 | /** 8 | * Schema for listing component contracts 9 | */ 10 | export const listComponentContractsSchema: ToolSchemaOptions = { 11 | name: 'list_component_contracts', 12 | description: 13 | 'List all available component contracts in the .cursor/tmp/contracts directory.', 14 | inputSchema: createProjectAnalysisSchema(), 15 | annotations: { 16 | title: 'List Component Contracts', 17 | ...COMMON_ANNOTATIONS.readOnly, 18 | }, 19 | }; 20 | ``` -------------------------------------------------------------------------------- /testing/utils/src/lib/execute-process-helper.mock.ts: -------------------------------------------------------------------------------- ```typescript 1 | import path from 'node:path'; 2 | 3 | const asyncProcessPath = path.join(__dirname, './execute-process.mock.mjs'); 4 | 5 | /** 6 | * Helps to get an async process runner config for testing. 7 | * 8 | * @param cfg can contain up to three properties for the async process runner 9 | */ 10 | export function getAsyncProcessRunnerConfig(cfg?: { 11 | throwError?: boolean; 12 | interval?: number; 13 | runs?: number; 14 | }) { 15 | const args = [ 16 | asyncProcessPath, 17 | cfg?.interval ? cfg.interval + '' : '100', 18 | cfg?.runs ? cfg.runs + '' : '4', 19 | cfg?.throwError ? '1' : '0', 20 | ]; 21 | return { command: 'node', args }; 22 | } 23 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/src/lib/stylesheet.visitor.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Comment, Container, Declaration, Rule, AtRule } from 'postcss'; 2 | 3 | export interface CssAstVisitor<T = void> { 4 | // Called once for the root node 5 | visitRoot?: (root: Container) => T; 6 | 7 | // Called for @rule nodes: @media, @charset, etc. 8 | visitAtRule?: (atRule: AtRule) => T; 9 | 10 | // Called for standard CSS rule nodes: .btn, .box, etc. 11 | visitRule?: (rule: Rule) => T; 12 | 13 | // Called for property declarations: color: red, width: 100px, etc. 14 | visitDecl?: (decl: Declaration) => T; 15 | 16 | // Called for comment nodes: /* some comment */ 17 | visitComment?: (comment: Comment) => T; 18 | } 19 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/src/lib/runner/audits/ds-coverage/schema.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { z } from 'zod'; 2 | 3 | export const ComponentReplacementSchema = z.object( 4 | { 5 | componentName: z.string({ 6 | description: 'The class name of the component to search for', 7 | }), 8 | deprecatedCssClasses: z.array(z.string(), { 9 | description: 'List of deprecated CSS classes for this component', 10 | }), 11 | docsUrl: z 12 | .string({ description: 'URL to the component documentation' }) 13 | .optional(), 14 | }, 15 | { description: 'Array of components and their deprecated CSS classes' }, 16 | ); 17 | 18 | export type ComponentReplacement = z.infer<typeof ComponentReplacementSchema>; 19 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/storybook-host-app/src/components/segmented-control/segmented-control.component.mdx: -------------------------------------------------------------------------------- ```markdown 1 | import { Meta } from '@storybook/blocks'; 2 | 3 | import * as SegmentedControlStories from './segmented-control.component.stories'; 4 | import OverviewTab from './segmented-control-tabs/overview.mdx'; 5 | import ExamplesTab from './segmented-control-tabs/examples.mdx'; 6 | import ApiTab from './segmented-control-tabs/api.mdx'; 7 | import { ComponentDocTabs } from '../../../../shared-storybook-utils/src/lib/component-doc-tabs/component-doc-tabs.mdx'; 8 | 9 | <Meta of={SegmentedControlStories} /> 10 | 11 | # Segmented Control Component 12 | 13 | <ComponentDocTabs 14 | OverviewTab={OverviewTab} 15 | ExamplesTab={ExamplesTab} 16 | ApiTab={ApiTab} 17 | /> 18 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/src/lib/runner/create-runner.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { AuditOutputs } from '@code-pushup/models'; 2 | import { parseAngularUnit } from '@push-based/angular-ast-utils'; 3 | import { dsCompCoverageAuditOutputs } from './audits/ds-coverage/ds-coverage.audit.js'; 4 | import { ComponentCoverageRunnerOptions } from './schema.js'; 5 | 6 | export type CreateRunnerConfig = ComponentCoverageRunnerOptions; 7 | 8 | export async function runnerFunction({ 9 | directory, 10 | dsComponents, 11 | }: CreateRunnerConfig): Promise<AuditOutputs> { 12 | const parsedComponents = await parseAngularUnit(directory, 'component'); 13 | 14 | return dsCompCoverageAuditOutputs(dsComponents, parsedComponents); 15 | } 16 | ``` -------------------------------------------------------------------------------- /packages/shared/styles-ast-utils/jest.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { readFileSync } from 'fs'; 2 | 3 | // Reading the SWC compilation config for the spec files 4 | const swcJestConfig = JSON.parse( 5 | readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8'), 6 | ); 7 | 8 | // Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves 9 | swcJestConfig.swcrc = false; 10 | 11 | export default { 12 | displayName: '@push-based/styles-ast-utils', 13 | preset: '../../../jest.preset.mjs', 14 | testEnvironment: 'node', 15 | transform: { 16 | '^.+\\.[tj]s$': ['@swc/jest', swcJestConfig], 17 | }, 18 | moduleFileExtensions: ['ts', 'js', 'html'], 19 | coverageDirectory: 'test-output/jest/coverage', 20 | }; 21 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/jest.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { readFileSync } from 'fs'; 2 | 3 | // Reading the SWC compilation config for the spec files 4 | const swcJestConfig = JSON.parse( 5 | readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8'), 6 | ); 7 | 8 | // Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves 9 | swcJestConfig.swcrc = false; 10 | 11 | export default { 12 | displayName: '@push-based/angular-ast-utils', 13 | preset: '../../../jest.preset.mjs', 14 | testEnvironment: 'node', 15 | transform: { 16 | '^.+\\.[tj]s$': ['@swc/jest', swcJestConfig], 17 | }, 18 | moduleFileExtensions: ['ts', 'js', 'html'], 19 | coverageDirectory: 'test-output/jest/coverage', 20 | }; 21 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/external-files-missing.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-external-files-missing', 5 | standalone: true, 6 | templateUrl: './non-existent-template.html', // This file doesn't exist 7 | styleUrls: [ 8 | './missing-styles.css', // This file doesn't exist 9 | './another-missing-style.scss', // This file doesn't exist 10 | '../shared/non-existent-shared.css' // This file doesn't exist 11 | ] 12 | }) 13 | export class ExternalFilesMissingComponent { 14 | title = 'External Files Missing Component'; 15 | message = 'This component references non-existent external files'; 16 | } ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/jest.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { readFileSync } from 'fs'; 2 | 3 | // Reading the SWC compilation config for the spec files 4 | const swcJestConfig = JSON.parse( 5 | readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8'), 6 | ); 7 | 8 | // Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves 9 | swcJestConfig.swcrc = false; 10 | 11 | export default { 12 | displayName: '@push-based/typescript-ast-utils', 13 | preset: '../../../jest.preset.mjs', 14 | testEnvironment: 'node', 15 | transform: { 16 | '^.+\\.[tj]s$': ['@swc/jest', swcJestConfig], 17 | }, 18 | moduleFileExtensions: ['ts', 'js', 'html'], 19 | coverageDirectory: 'test-output/jest/coverage', 20 | }; 21 | ``` -------------------------------------------------------------------------------- /packages/shared/typescript-ast-utils/jest.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { readFileSync } from 'fs'; 2 | 3 | // Reading the SWC compilation config for the spec files 4 | const swcJestConfig = JSON.parse( 5 | readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8'), 6 | ); 7 | 8 | // Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves 9 | swcJestConfig.swcrc = false; 10 | 11 | export default { 12 | displayName: '@push-based/typescript-ast-utils', 13 | preset: '../../../jest.preset.mjs', 14 | testEnvironment: 'node', 15 | transform: { 16 | '^.+\\.[tj]s$': ['@swc/jest', swcJestConfig], 17 | }, 18 | moduleFileExtensions: ['ts', 'js', 'html'], 19 | coverageDirectory: 'test-output/jest/coverage', 20 | }; 21 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/missing-method.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-missing-method', 5 | standalone: true, 6 | template: ` 7 | <div> 8 | <h2>Missing Method Test</h2> 9 | <button (click)="nonExistentMethod()">Click me</button> 10 | <p>{{ getDisplayText() }}</p> 11 | <div>{{ calculateValue(42) }}</div> 12 | </div> 13 | `, 14 | styles: [` 15 | div { 16 | padding: 20px; 17 | border: 1px solid red; 18 | } 19 | `] 20 | }) 21 | export class MissingMethodComponent { 22 | title = 'Missing Method Component'; 23 | 24 | // Note: nonExistentMethod(), getDisplayText(), and calculateValue() are called in template but not defined 25 | } ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/refactoring-tests/group-4/multi-violation-test.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-multi-violation-test', 5 | templateUrl: './multi-violation-test.component.html', 6 | styleUrls: ['./multi-violation-test.component.scss'], 7 | standalone: true 8 | }) 9 | export class MultiViolationTestComponent { 10 | activeTab = 0; 11 | showCard = true; 12 | notifications = 5; 13 | 14 | constructor() { 15 | console.log('MultiViolationTestComponent initialized'); 16 | } 17 | 18 | switchTab(index: number) { 19 | this.activeTab = index; 20 | } 21 | 22 | toggleCard() { 23 | this.showCard = !this.showCard; 24 | } 25 | 26 | handleButtonClick() { 27 | console.log('Legacy button clicked'); 28 | } 29 | } 30 | ``` -------------------------------------------------------------------------------- /packages/shared/angular-ast-utils/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": false, 9 | "forceConsistentCasingInFileNames": true, 10 | "types": ["node"] 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "references": [ 14 | { 15 | "path": "../typescript-ast-utils/tsconfig.lib.json" 16 | }, 17 | { 18 | "path": "../utils/tsconfig.lib.json" 19 | }, 20 | { 21 | "path": "../styles-ast-utils/tsconfig.lib.json" 22 | } 23 | ], 24 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 25 | } 26 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/circular-dependency.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | import { CircularDependencyComponent } from './circular-dependency.component'; 3 | 4 | @Component({ 5 | selector: 'app-circular-dependency', 6 | standalone: true, 7 | imports: [CircularDependencyComponent], 8 | template: ` 9 | <div> 10 | <h2>Circular Dependency Test</h2> 11 | <p>This component imports itself!</p> 12 | <app-circular-dependency></app-circular-dependency> 13 | </div> 14 | `, 15 | styles: [` 16 | div { 17 | border: 2px solid orange; 18 | margin: 5px; 19 | padding: 10px; 20 | } 21 | `] 22 | }) 23 | export class CircularDependencyComponent { 24 | title = 'Circular Dependency Component'; 25 | } ``` -------------------------------------------------------------------------------- /testing/utils/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": false, 9 | "types": ["node", "vite/client"] 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "references": [], 13 | "exclude": [ 14 | "vite.config.ts", 15 | "vite.config.mts", 16 | "vitest.config.ts", 17 | "vitest.config.mts", 18 | "src/**/*.test.ts", 19 | "src/**/*.spec.ts", 20 | "src/**/*.test.tsx", 21 | "src/**/*.spec.tsx", 22 | "src/**/*.test.js", 23 | "src/**/*.spec.js", 24 | "src/**/*.test.jsx", 25 | "src/**/*.spec.jsx" 26 | ] 27 | } 28 | ``` -------------------------------------------------------------------------------- /testing/vitest-setup/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": false, 9 | "types": ["node", "vite/client"] 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": [ 13 | "vite.config.ts", 14 | "vite.config.mts", 15 | "vitest.config.ts", 16 | "vitest.config.mts", 17 | "src/**/*.test.ts", 18 | "src/**/*.spec.ts", 19 | "src/**/*.test.tsx", 20 | "src/**/*.spec.tsx", 21 | "src/**/*.test.js", 22 | "src/**/*.spec.js", 23 | "src/**/*.test.jsx", 24 | "src/**/*.spec.jsx" 25 | ], 26 | "references": [] 27 | } 28 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo/prompt.md: -------------------------------------------------------------------------------- ```markdown 1 | ## Prompt 2 | 3 | Refactor the folder packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo. 4 | Look for btn and btn-primary class and replace them with the button component in the same folder. Use the coverage MCP tool to list used classes. directly call the tool before gathereing more context 5 | 6 | ## Tool Request 7 | 8 | ```bash 9 | { 10 | "cwd": "/Users/michael_hladky/WebstormProjects/ds-mcp", 11 | "directory": "packages/shared/ds-component-coverage/mocks/fixtures/e2e/demo", 12 | "dsComponents": [ 13 | { 14 | "componentName": "Button", 15 | "deprecatedCssClasses": [ 16 | "btn", 17 | "btn-primary" 18 | ] 19 | } 20 | ] 21 | } 22 | ``` 23 | 24 | ## Tool Response 25 | 26 | ```bash 27 | 28 | ``` 29 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/src/lib/runner/audits/ds-coverage/class-usage.utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Asset, visitEachTmplChild } from '@push-based/angular-ast-utils'; 2 | import { ComponentReplacement } from './schema.js'; 3 | import { ClassUsageVisitor } from './class-usage.visitor.js'; 4 | import type { 5 | ParsedTemplate, 6 | TmplAstNode, 7 | } from '@angular/compiler' with { 'resolution-mode': 'import' }; 8 | 9 | export async function getClassUsageIssues( 10 | componentReplacement: ComponentReplacement, 11 | asset: Asset<ParsedTemplate>, 12 | ) { 13 | const visitor = new ClassUsageVisitor(componentReplacement, asset.startLine); 14 | const parsedTemplate = await asset.parse(); 15 | visitEachTmplChild(parsedTemplate.nodes as TmplAstNode[], visitor); 16 | 17 | return visitor.getIssues(); 18 | } 19 | ``` -------------------------------------------------------------------------------- /testing/setup/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 8 | "emitDeclarationOnly": false, 9 | "types": ["node", "vite/client"] 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": [ 13 | "vite.config.ts", 14 | "vite.config.mts", 15 | "vitest.config.ts", 16 | "vitest.config.mts", 17 | "vitest.integration.config.mts", 18 | "src/**/*.test.ts", 19 | "src/**/*.spec.ts", 20 | "src/**/*.test.tsx", 21 | "src/**/*.spec.tsx", 22 | "src/**/*.test.js", 23 | "src/**/*.spec.js", 24 | "src/**/*.test.jsx", 25 | "src/**/*.spec.jsx" 26 | ], 27 | "references": [] 28 | } 29 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { dsComponentCoveragePlugin } from './lib/ds-component-coverage.plugin.js'; 2 | export { 3 | runnerFunction, 4 | type CreateRunnerConfig, 5 | } from './lib/runner/create-runner.js'; 6 | export { 7 | dsComponentCoveragePlugin, 8 | type DsComponentUsagePluginConfig, 9 | } from './lib/ds-component-coverage.plugin.js'; 10 | export { getAngularDsUsageCategoryRefs } from './lib/utils.js'; 11 | export { ANGULAR_DS_USAGE_PLUGIN_SLUG } from './lib/constants.js'; 12 | export default dsComponentCoveragePlugin; 13 | export type { 14 | ComponentReplacement, 15 | ComponentReplacementSchema, 16 | } from './lib/runner/audits/ds-coverage/schema.js'; 17 | export { ComponentCoverageRunnerOptionsSchema } from './lib/runner/schema.js'; 18 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/tsconfig.lib.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "baseUrl": ".", 7 | "rootDir": "src", 8 | "outDir": "dist", 9 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 10 | "emitDeclarationOnly": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "types": ["node"] 13 | }, 14 | "include": ["src/**/*.ts"], 15 | "references": [ 16 | { 17 | "path": "../models/tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "../styles-ast-utils/tsconfig.lib.json" 21 | }, 22 | { 23 | "path": "../angular-ast-utils/tsconfig.lib.json" 24 | } 25 | ], 26 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 27 | } 28 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format/code-pushup.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ComponentReplacement } from '../../../../src/index'; 2 | import { dsComponentUsagePluginCoreConfig } from '../../../../src/core.config'; 3 | 4 | const dsComponents: ComponentReplacement[] = [ 5 | { 6 | componentName: 'DSButton', 7 | deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button'], 8 | docsUrl: 9 | 'https://storybook.company.com/latest/?path=/docs/components-button--overview', 10 | }, 11 | ]; 12 | export default { 13 | persist: { 14 | outputDir: '.code-pushup/ds-component-coverage/style-format', 15 | format: ['json', 'md'], 16 | }, 17 | ...(await dsComponentUsagePluginCoreConfig({ 18 | directory: 19 | 'packages/shared/ds-component-coverage/mocks/fixtures/e2e/style-format', 20 | dsComponents, 21 | })), 22 | }; 23 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/src/lib/utils.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Audit, CategoryRef } from '@code-pushup/models'; 2 | import { ANGULAR_DS_USAGE_PLUGIN_SLUG } from './constants.js'; 3 | import { getCompUsageAudits } from './runner/audits/ds-coverage/utils.js'; 4 | import { ComponentReplacement } from './runner/audits/ds-coverage/schema.js'; 5 | 6 | export function getAudits( 7 | componentReplacements: ComponentReplacement[], 8 | ): Audit[] { 9 | return [...getCompUsageAudits(componentReplacements)]; 10 | } 11 | 12 | export function getAngularDsUsageCategoryRefs( 13 | componentReplacements: ComponentReplacement[], 14 | ): CategoryRef[] { 15 | return getAudits(componentReplacements).map(({ slug }) => ({ 16 | slug, 17 | plugin: ANGULAR_DS_USAGE_PLUGIN_SLUG, 18 | type: 'audit', 19 | weight: 1, 20 | })); 21 | } 22 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number/code-pushup.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ComponentReplacement } from '../../../../src/index'; 2 | import { dsComponentUsagePluginCoreConfig } from '../../../../src/core.config'; 3 | 4 | const dsComponents: ComponentReplacement[] = [ 5 | { 6 | componentName: 'DSButton', 7 | deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button'], 8 | docsUrl: 9 | 'https://storybook.company.com/latest/?path=/docs/components-button--overview', 10 | }, 11 | ]; 12 | 13 | export default { 14 | persist: { 15 | outputDir: '.code-pushup/ds-component-coverage/line-number', 16 | format: ['json', 'md'], 17 | }, 18 | ...(await dsComponentUsagePluginCoreConfig({ 19 | directory: 20 | './packages/shared/ds-component-coverage/mocks/fixtures/e2e/line-number', 21 | dsComponents, 22 | })), 23 | }; 24 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/design-system/ui/segmented-control/src/segmented-control.token.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { InjectionToken, Provider } from '@angular/core'; 2 | 3 | export type DsSegmentedControlOptions = { 4 | /* 5 | * Whether the control should take up the full width of the container. 6 | */ 7 | fullWidth: boolean; 8 | }; 9 | 10 | const DEFAULT_SC_OPTIONS: DsSegmentedControlOptions = { 11 | fullWidth: false, 12 | }; 13 | 14 | export const SEGMENTED_CONTROL_OPTIONS_TOKEN = 15 | new InjectionToken<DsSegmentedControlOptions>('SC_OPTIONS', { 16 | providedIn: 'root', 17 | factory: () => DEFAULT_SC_OPTIONS, 18 | }); 19 | 20 | export const provideSegmentedControlOptions = ( 21 | options: Partial<DsSegmentedControlOptions>, 22 | ) => 23 | ({ 24 | provide: SEGMENTED_CONTROL_OPTIONS_TOKEN, 25 | useValue: { ...DEFAULT_SC_OPTIONS, ...options }, 26 | }) satisfies Provider; 27 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location/code-pushup.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ComponentReplacement } from '../../../../src/index'; 2 | import { dsComponentUsagePluginCoreConfig } from '../../../../src/core.config'; 3 | 4 | const dsComponents: ComponentReplacement[] = [ 5 | { 6 | componentName: 'DSButton', 7 | deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button'], 8 | docsUrl: 9 | 'https://storybook.company.com/latest/?path=/docs/components-button--overview', 10 | }, 11 | ]; 12 | export default { 13 | persist: { 14 | outputDir: '.code-pushup/ds-component-coverage/asset-location', 15 | format: ['json', 'md'], 16 | }, 17 | ...(await dsComponentUsagePluginCoreConfig({ 18 | directory: 19 | './packages/shared/ds-component-coverage/mocks/fixtures/e2e/asset-location', 20 | dsComponents, 21 | })), 22 | }; 23 | ``` -------------------------------------------------------------------------------- /packages/shared/ds-component-coverage/mocks/fixtures/e2e/template-syntax/code-pushup.config.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ComponentReplacement } from '../../../../src/index'; 2 | import { dsComponentUsagePluginCoreConfig } from '../../../../src/core.config'; 3 | 4 | const dsComponents: ComponentReplacement[] = [ 5 | { 6 | componentName: 'DSButton', 7 | deprecatedCssClasses: ['btn', 'btn-primary', 'legacy-button'], 8 | docsUrl: 9 | 'https://storybook.company.com/latest/?path=/docs/components-button--overview', 10 | }, 11 | ]; 12 | 13 | export default { 14 | persist: { 15 | outputDir: '.code-pushup/ds-component-coverage/template-syntax', 16 | format: ['json', 'md'], 17 | }, 18 | ...(await dsComponentUsagePluginCoreConfig({ 19 | directory: 20 | 'packages/shared/ds-component-coverage/mocks/fixtures/e2e/template-syntax', 21 | dsComponents, 22 | })), 23 | }; 24 | ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/invalid-template-syntax.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-invalid-syntax', 5 | standalone: false, 6 | template: ` 7 | <div> 8 | <h2>Invalid Template Syntax Test</h2> 9 | <p>{{ unclosedInterpolation 10 | <div [attr.data-value="missingQuotes>Content</div> 11 | <button (click)="method(">Malformed event binding</button> 12 | <input [(ngModel)]="value" [disabled]="true" [readonly]="false" /> 13 | <span *ngFor="let item of items; let i = index">{{ item.name }}</span> 14 | <div [ngClass]="{active: true, disabled: }">Class binding error</div> 15 | </div> 16 | `, 17 | styles: [` 18 | div { margin: 10px; } 19 | `] 20 | }) 21 | export class InvalidTemplateSyntaxComponent { 22 | value = ''; 23 | items = [{ name: 'test' }]; 24 | } ``` -------------------------------------------------------------------------------- /packages/minimal-repo/packages/application/src/app/components/validation-tests/wrong-property-binding.component.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-wrong-property', 5 | standalone: true, 6 | template: ` 7 | <div> 8 | <h2>Wrong Property Binding Test</h2> 9 | <p>{{ nonExistentProperty }}</p> 10 | <input [value]="undefinedValue" /> 11 | <div [class.active]="isActiveButNotDefined"> 12 | Status: {{ status.value }} 13 | </div> 14 | <span [hidden]="hiddenFlag">{{ missingData }}</span> 15 | </div> 16 | `, 17 | styles: [` 18 | .active { background: green; } 19 | `] 20 | }) 21 | export class WrongPropertyBindingComponent { 22 | title = 'Wrong Property Component'; 23 | 24 | // Note: nonExistentProperty, undefinedValue, isActiveButNotDefined, status, hiddenFlag, and missingData are used in template but not defined 25 | } ``` -------------------------------------------------------------------------------- /packages/shared/utils/tsconfig.spec.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/vitest", 5 | "types": [ 6 | "vitest/globals", 7 | "vitest/importMeta", 8 | "vite/client", 9 | "node", 10 | "vitest" 11 | ] 12 | }, 13 | "references": [ 14 | { 15 | "path": "../../../testing/utils/tsconfig.json" 16 | }, 17 | { 18 | "path": "../../../testing/vitest-setup/tsconfig.json" 19 | } 20 | ], 21 | "include": [ 22 | "vite.config.ts", 23 | "vite.config.mts", 24 | "vitest.config.ts", 25 | "vitest.config.mts", 26 | "src/**/*.test.ts", 27 | "src/**/*.spec.ts", 28 | "src/**/*.test.tsx", 29 | "src/**/*.spec.tsx", 30 | "src/**/*.test.js", 31 | "src/**/*.spec.js", 32 | "src/**/*.test.jsx", 33 | "src/**/*.spec.jsx", 34 | "src/**/*.d.ts" 35 | ] 36 | } 37 | ```