├── .editorconfig ├── .github ├── CODEOWNERS ├── renovate.json └── workflows │ ├── assign-author.yml │ ├── auto-merge.yml │ ├── ci.yml │ ├── deploy.yml │ ├── ready-to-merge.yml │ └── release.yml ├── .gitignore ├── .release-it.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── apps └── demo │ ├── jest.config.ts │ ├── project.json │ ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.less │ │ ├── app.component.ts │ │ ├── getting-started │ │ │ ├── index.html │ │ │ └── index.ts │ │ ├── logo │ │ │ ├── index.html │ │ │ ├── index.less │ │ │ └── index.ts │ │ ├── pages.ts │ │ ├── pages │ │ │ ├── classes │ │ │ │ ├── index.html │ │ │ │ ├── index.ts │ │ │ │ └── samples │ │ │ │ │ ├── accessors.ts │ │ │ │ │ ├── constructors.ts │ │ │ │ │ ├── decorators.ts │ │ │ │ │ ├── methods.ts │ │ │ │ │ └── properties.ts │ │ │ ├── enums │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── functions │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── get-bootstrap-function │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── get-main-module │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── imports-and-exports │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── inject-sample │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── interfaces │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── source-files │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ ├── types │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ │ └── variables │ │ │ │ ├── index.html │ │ │ │ └── index.ts │ │ └── routes.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-384x384.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── images │ │ │ ├── by.svg │ │ │ ├── github.svg │ │ │ └── ng-morph.png │ │ ├── mstile-150x150.png │ │ ├── safari-pinned-tab.svg │ │ └── site.webmanifest │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ └── styles.less │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── jest.preset.js ├── libs └── ng-morph │ ├── .babelrc │ ├── jest.config.ts │ ├── ng-morph.png │ ├── package.json │ ├── project.json │ ├── src │ ├── accessors │ │ ├── add-accessors.ts │ │ ├── edit-accessors.ts │ │ ├── get-accessors.ts │ │ ├── index.ts │ │ └── remove-accessors.ts │ ├── classes │ │ ├── add-classes.ts │ │ ├── edit-classes.ts │ │ ├── get-classes.ts │ │ ├── index.ts │ │ └── remove-classes.ts │ ├── constructors │ │ ├── add-constructors.ts │ │ ├── edit-constructors.ts │ │ ├── get-constructors.ts │ │ ├── index.ts │ │ └── remove-constructors.ts │ ├── decorators │ │ ├── add-decorators.ts │ │ ├── edit-decorators.ts │ │ ├── get-decorators.ts │ │ ├── index.ts │ │ └── remove-decorators.ts │ ├── enums │ │ ├── add-enums.ts │ │ ├── edit-enums.ts │ │ ├── get-enums.ts │ │ ├── index.ts │ │ └── remove-enums.ts │ ├── exports │ │ ├── add-exports.ts │ │ ├── edit-exports.ts │ │ ├── get-exports.ts │ │ ├── index.ts │ │ └── remove-exports.ts │ ├── functions │ │ ├── add-functions.ts │ │ ├── edit-functions.ts │ │ ├── get-functions.ts │ │ ├── index.ts │ │ └── remove-functions.ts │ ├── imports │ │ ├── add-imports.ts │ │ ├── edit-imports.ts │ │ ├── get-imports.ts │ │ ├── index.ts │ │ └── remove-imports.ts │ ├── index.ts │ ├── interfaces │ │ ├── add-interfaces.ts │ │ ├── edit-interfaces.ts │ │ ├── get-interfaces.ts │ │ ├── index.ts │ │ └── remove-interfaces.ts │ ├── json │ │ ├── consts.ts │ │ ├── dependencies.ts │ │ ├── get-project-targets.ts │ │ ├── index.ts │ │ ├── insertion-index.ts │ │ ├── json-file-content.ts │ │ ├── json-file.ts │ │ └── json-path.ts │ ├── methods │ │ ├── add-methods.ts │ │ ├── edit-methods.ts │ │ ├── get-methods.ts │ │ ├── index.ts │ │ └── remove-methods.ts │ ├── ng │ │ ├── bootstrap │ │ │ ├── add-provider-to-bootstrap-application-fn.ts │ │ │ ├── get-bootstrap-application-fn.ts │ │ │ ├── get-bootstrap-fn.ts │ │ │ └── index.ts │ │ ├── component │ │ │ ├── add-import-to-component.ts │ │ │ ├── add-provider-to-component.ts │ │ │ ├── add-style-url-to-component.ts │ │ │ └── index.ts │ │ ├── directive │ │ │ ├── add-provider-to-directive.ts │ │ │ └── index.ts │ │ ├── helpers │ │ │ ├── get-main-module.ts │ │ │ ├── index.ts │ │ │ ├── is-standalone-component.ts │ │ │ ├── ng-component.ts │ │ │ ├── ng-module.ts │ │ │ ├── push-to-decorator-array-property.ts │ │ │ └── push-to-object-literal-array-property.ts │ │ ├── index.ts │ │ └── module │ │ │ ├── add-bootstrap-to-ng-module.ts │ │ │ ├── add-declaration-to-ng-module.ts │ │ │ ├── add-entry-component-to-ng-module.ts │ │ │ ├── add-export-to-ng-module.ts │ │ │ ├── add-import-to-ng-module.ts │ │ │ ├── add-provider-to-ng-module.ts │ │ │ ├── add-schema-to-ng-module.ts │ │ │ └── index.ts │ ├── params │ │ ├── add-params.ts │ │ ├── edit-params.ts │ │ ├── get-params.ts │ │ ├── index.ts │ │ └── remove-params.ts │ ├── project │ │ ├── create-project.ts │ │ ├── devkit-file-system.ts │ │ ├── file-system.ts │ │ ├── index.ts │ │ ├── ng-cli-project-options.ts │ │ ├── ng-cli-project.ts │ │ ├── ng-morph-tree.ts │ │ ├── project.ts │ │ ├── save-project.ts │ │ └── update-recorder.ts │ ├── properties │ │ ├── add-properties.ts │ │ ├── edit-properties.ts │ │ ├── get-properties.ts │ │ ├── index.ts │ │ └── remove-properties.ts │ ├── source-file │ │ ├── create-source-file.ts │ │ ├── get-source-files.ts │ │ ├── index.ts │ │ └── move-source-file-paths.ts │ ├── type-aliases │ │ ├── add-type-aliases.ts │ │ ├── edit-type-aliases.ts │ │ ├── get-type-aliases.ts │ │ ├── index.ts │ │ └── remove-type-aliases.ts │ ├── utils │ │ ├── array-flat.ts │ │ ├── coerce-array.ts │ │ ├── colored-log.ts │ │ ├── filter-primitive.ts │ │ ├── get-declaration-creator.ts │ │ ├── get-declaration-editor.ts │ │ ├── get-declaration-getter.ts │ │ ├── get-declaration-remover.ts │ │ ├── index.ts │ │ ├── match-query.ts │ │ ├── pattern.ts │ │ ├── structure-editor.ts │ │ ├── structure-type.ts │ │ ├── structured-statement.ts │ │ └── throw-file-not-found.ts │ └── variables │ │ ├── add-variables.ts │ │ ├── edit-variables.ts │ │ ├── get-variables.ts │ │ ├── index.ts │ │ └── remove-variables.ts │ ├── tests │ ├── add-accessors.spec.ts │ ├── add-bootstrap-to-ng-module.spec.ts │ ├── add-classes.spec.ts │ ├── add-constructors.spec.ts │ ├── add-declaration-to-ng-module.spec.ts │ ├── add-decorators.spec.ts │ ├── add-entry-component-to-ng-module.spec.ts │ ├── add-enums.spec.ts │ ├── add-export-to-ng-module.spec.ts │ ├── add-exports.spec.ts │ ├── add-functions.spec.ts │ ├── add-import-to-component.spec.ts │ ├── add-import-to-ng-module.spec.ts │ ├── add-imports.spec.ts │ ├── add-interfaces.spec.ts │ ├── add-methods.spec.ts │ ├── add-params.spec.ts │ ├── add-properties.spec.ts │ ├── add-provider-to-bootstrap-application-fn.spec.ts │ ├── add-provider-to-component.spec.ts │ ├── add-provider-to-directive.spec.ts │ ├── add-provider-to-ng-module.spec.ts │ ├── add-schema-to-ng-module.spec.ts │ ├── add-style-url-to-component.spec.ts │ ├── add-type-aliases.spec.ts │ ├── add-variables.spec.ts │ ├── dependencies.spec.ts │ ├── edit-accessors.spec.ts │ ├── edit-classes.spec.ts │ ├── edit-constructors.spec.ts │ ├── edit-decorators.spec.ts │ ├── edit-enums.spec.ts │ ├── edit-exports.spec.ts │ ├── edit-functions.spec.ts │ ├── edit-imports.spec.ts │ ├── edit-interfaces.spec.ts │ ├── edit-methods.spec.ts │ ├── edit-params.spec.ts │ ├── edit-properties.spec.ts │ ├── edit-type-aliases.spec.ts │ ├── edit-variables.spec.ts │ ├── get-accessors.spec.ts │ ├── get-bootstrap-application-fn.spec.ts │ ├── get-bootstrap-fn.spec.ts │ ├── get-classes.spec.ts │ ├── get-constructors.spec.ts │ ├── get-decorators.spec.ts │ ├── get-enums.spec.ts │ ├── get-exports.spec.ts │ ├── get-functions.spec.ts │ ├── get-imports.spec.ts │ ├── get-interfaces.spec.ts │ ├── get-main-module.spec.ts │ ├── get-methods.spec.ts │ ├── get-params.spec.ts │ ├── get-project-targets.spec.ts │ ├── get-properties.spec.ts │ ├── get-source-files.spec.ts │ ├── get-type-aliases.spec.ts │ ├── get-variables.spec.ts │ ├── json-file-content.spec.ts │ ├── move-source-file-paths.spec.ts │ ├── ng-morph-tree.spec.ts │ ├── remove-accessors.spec.ts │ ├── remove-classes.spec.ts │ ├── remove-constructors.spec.ts │ ├── remove-decorators.spec.ts │ ├── remove-enums.spec.ts │ ├── remove-exports.spec.ts │ ├── remove-functions.spec.ts │ ├── remove-imports.spec.ts │ ├── remove-interfaces.spec.ts │ ├── remove-methods.spec.ts │ ├── remove-params.spec.ts │ ├── remove-properties.spec.ts │ ├── remove-type-aliases.spec.ts │ └── remove-variables.spec.ts │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── nx.json ├── package-lock.json ├── package.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | ij_typescript_spaces_within_imports = true 11 | 12 | [*.md] 13 | max_line_length = off 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | # ================================================================================== 3 | # ================================================================================== 4 | # @taiga-ui codeowners 5 | # ================================================================================== 6 | # ================================================================================== 7 | # 8 | # Configuration of code ownership and review approvals for the @taiga-ui repo. 9 | # 10 | # More info: https://help.github.com/articles/about-codeowners/ 11 | # 12 | 13 | * @waterplea @MarsiBarsi @vladimirpotekhin @nsbarsukov @mdlufy 14 | # will be requested for review when someone opens a pull request 15 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>taiga-family/renovate-config"], 4 | "packageRules": [ 5 | { 6 | "matchPackageNames": ["multimatch"], 7 | "allowedVersions": "=5.0.0" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/assign-author.yml: -------------------------------------------------------------------------------- 1 | name: 🤖 PR author as an assignee 2 | on: 3 | pull_request: 4 | types: [opened] 5 | 6 | jobs: 7 | assign: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4.2.2 11 | - uses: taiga-family/ci/actions/setup/variables@v1.114.0 12 | - uses: toshimaru/auto-author-assign@v2.1.1 13 | continue-on-error: true 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }} 17 | cancel-in-progress: true 18 | -------------------------------------------------------------------------------- /.github/workflows/auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: 🤖 PR auto merge 2 | on: 3 | pull_request: 4 | 5 | env: 6 | JOBS_NAME: '[ "ci" ]' 7 | 8 | jobs: 9 | setup: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | matrix: ${{ steps.matrix.outputs.value }} 13 | steps: 14 | - uses: actions/checkout@v4.2.2 15 | - uses: taiga-family/ci/actions/setup/variables@v1.114.0 16 | - id: matrix 17 | run: echo "value=$JOBS_NAME" >> $GITHUB_OUTPUT 18 | 19 | wait: 20 | needs: [setup] 21 | runs-on: ubuntu-latest 22 | strategy: 23 | fail-fast: true 24 | matrix: 25 | value: ${{ fromJSON(needs.setup.outputs.matrix) }} 26 | steps: 27 | - uses: taiga-family/ci/actions/run/wait-job@v1.114.0 28 | with: 29 | token: ${{ secrets.GITHUB_TOKEN }} 30 | job: ${{ matrix.value }} 31 | 32 | approve: 33 | needs: [wait] 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v4.2.2 37 | - uses: taiga-family/ci/actions/setup/variables@v1.114.0 38 | - uses: taiga-family/ci/actions/auto/approve/double@v1.114.0 39 | if: env.IS_TAIGA_FAMILY_BOT_PR_AUTHOR == 'true' 40 | with: 41 | token1: ${{ secrets.GITHUB_TOKEN }} 42 | token2: ${{ secrets.TAIGA_FAMILY_APPROVE_BOT_PAT }} 43 | - uses: taiga-family/ci/actions/run/merge@v1.114.0 44 | if: env.IS_TAIGA_FAMILY_BOT_PR_AUTHOR == 'true' 45 | with: 46 | token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }} 47 | 48 | concurrency: 49 | group: ${{ github.workflow }}-${{ github.ref }} 50 | cancel-in-progress: true 51 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | ci: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4.2.2 13 | with: 14 | persist-credentials: false 15 | - uses: taiga-family/ci/actions/setup/variables@v1.114.0 16 | - uses: taiga-family/ci/actions/setup/node@v1.114.0 17 | - run: | 18 | if [[ "${{ env.SUPPORT_AUTO_PUSH }}" == "true" ]]; then 19 | npm run prettier -- --write 20 | npm run stylelint -- --fix 21 | npm run lint -- --fix 22 | else 23 | npm run prettier -- --check 24 | npm run stylelint 25 | npm run lint 26 | fi 27 | 28 | - run: | 29 | npm run build 30 | npm test 31 | 32 | - uses: taiga-family/ci/actions/auto/push@v1.114.0 33 | with: 34 | token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }} 35 | 36 | concurrency: 37 | group: ${{ github.workflow }}-${{ github.ref }} 38 | cancel-in-progress: true 39 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy demo 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4.2.2 12 | - uses: taiga-family/ci/actions/setup/variables@v1.114.0 13 | - uses: taiga-family/ci/actions/setup/node@v1.114.0 14 | - run: npm run build:demo 15 | - uses: taiga-family/ci/actions/deploy/github-pages@v1.114.0 16 | with: 17 | token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }} 18 | folder: dist/apps/demo 19 | 20 | concurrency: 21 | group: ${{ github.workflow }}-${{ github.ref }} 22 | cancel-in-progress: true 23 | -------------------------------------------------------------------------------- /.github/workflows/ready-to-merge.yml: -------------------------------------------------------------------------------- 1 | name: 🤖 PR is ready to merge 2 | on: 3 | pull_request_review: 4 | types: [submitted] 5 | 6 | jobs: 7 | label-when-approved: 8 | name: Label when approved 9 | runs-on: ubuntu-latest 10 | if: github.event.review.state == 'approved' 11 | steps: 12 | - uses: actions/checkout@v4.2.2 13 | - uses: taiga-family/ci/actions/setup/variables@v1.114.0 14 | - uses: taiga-family/ci/actions/auto/label-when-approved@v1.114.0 15 | with: 16 | approvals: 1 17 | token: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | concurrency: 20 | group: ${{ github.workflow }}-${{ github.ref }} 21 | cancel-in-progress: true 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: ⚠️ Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | mode: 7 | type: choice 8 | description: Bump version as requested 9 | required: true 10 | options: 11 | - minor 12 | - patch 13 | - major 14 | schedule: 15 | - cron: '0 7 * * 1' 16 | 17 | jobs: 18 | release: 19 | runs-on: ubuntu-latest 20 | if: "!contains(github.event.head_commit.message, 'chore(release)')" 21 | steps: 22 | - uses: actions/checkout@v4.2.2 23 | - uses: taiga-family/ci/actions/run/release-it@v1.114.0 24 | id: release-it 25 | with: 26 | ref: ${{ github.ref }} 27 | mode: ${{ github.event.inputs.mode }} 28 | npmToken: ${{ secrets.NPM_TOKEN }} 29 | githubToken: ${{ secrets.TAIGA_FAMILY_BOT_PAT }} 30 | 31 | - uses: taiga-family/ci/actions/run/read-package-json@v1.114.0 32 | id: info 33 | 34 | - name: Announce to Telegram 35 | if: steps.release-it.outputs.released == 'true' 36 | uses: taiga-family/ci/actions/messenger/telegram/announce@v1.114.0 37 | with: 38 | chatId: ${{ secrets.TAIGA_TELEGRAM_CHAT_ID }} 39 | topicId: ${{ secrets.TAIGA_TELEGRAM_CHAT_THREAD_ID }} 40 | token: ${{ secrets.TAIGA_TELEGRAM_BOT_TOKEN }} 41 | version: v${{ steps.info.outputs.version }} 42 | textLink: ${{ steps.info.outputs.name }} 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-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 | /.angular 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | yarn-error.log 35 | testem.log 36 | /typings 37 | 38 | # System Files 39 | .DS_Store 40 | Thumbs.db 41 | 42 | .nx 43 | .angular 44 | -------------------------------------------------------------------------------- /.release-it.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@taiga-ui/release-it-config'); 2 | -------------------------------------------------------------------------------- /apps/demo/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | module.exports = { 3 | displayName: 'demo', 4 | preset: '../../jest.preset.js', 5 | globals: {}, 6 | coverageDirectory: '../../coverage/apps/demo', 7 | snapshotSerializers: [ 8 | 'jest-preset-angular/build/serializers/no-ng-attributes', 9 | 'jest-preset-angular/build/serializers/ng-snapshot', 10 | 'jest-preset-angular/build/serializers/html-comment', 11 | ], 12 | transform: { 13 | '^.+\\.(ts|js|html)$': [ 14 | 'jest-preset-angular', 15 | { 16 | stringifyContentPathRegex: '\\.(html|svg)$', 17 | 18 | tsconfig: '/tsconfig.spec.json', 19 | }, 20 | ], 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /apps/demo/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | npm-link 13 | 14 | 15 | 16 | 24 | 29 | GitHub 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /apps/demo/src/app/app.component.less: -------------------------------------------------------------------------------- 1 | :host { 2 | font: var(--tui-font-text-m); 3 | } 4 | 5 | .npm-link { 6 | margin-top: 0.5rem; 7 | margin-left: 0.75rem; 8 | } 9 | 10 | .github-link { 11 | font-weight: bold; 12 | block-size: 1.5rem; 13 | } 14 | 15 | .github { 16 | inline-size: 1.5rem; 17 | block-size: 1.5rem; 18 | margin: 0 4px 0 16px; 19 | vertical-align: -0.375rem; 20 | } 21 | -------------------------------------------------------------------------------- /apps/demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | import {TuiLink} from '@taiga-ui/core'; 4 | import {HighlightModule} from 'ngx-highlightjs'; 5 | 6 | @Component({ 7 | standalone: true, 8 | selector: 'app-root', 9 | imports: [HighlightModule, TuiAddonDoc, TuiLink], 10 | templateUrl: './app.component.html', 11 | styleUrls: ['./app.component.less'], 12 | changeDetection: ChangeDetectionStrategy.OnPush, 13 | }) 14 | export class AppComponent {} 15 | -------------------------------------------------------------------------------- /apps/demo/src/app/logo/index.html: -------------------------------------------------------------------------------- 1 | 6 | ng-morph 7 | by T-Bank 12 | -------------------------------------------------------------------------------- /apps/demo/src/app/logo/index.less: -------------------------------------------------------------------------------- 1 | @import '~@taiga-ui/core/styles/taiga-ui-local'; 2 | 3 | :host { 4 | display: flex; 5 | align-items: center; 6 | 7 | @media @tui-mobile { 8 | font-size: 0; 9 | } 10 | } 11 | 12 | .logo { 13 | inline-size: 1.875rem; 14 | margin-right: 0.625rem; 15 | } 16 | 17 | .by { 18 | margin-left: 0.875rem; 19 | 20 | @media @tui-mobile { 21 | display: none; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/demo/src/app/logo/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {PolymorpheusComponent} from '@taiga-ui/polymorpheus'; 3 | 4 | @Component({ 5 | standalone: true, 6 | templateUrl: './index.html', 7 | styleUrls: ['./index.less'], 8 | changeDetection: ChangeDetectionStrategy.OnPush, 9 | }) 10 | export class LogoComponent {} 11 | 12 | export const LOGO_CONTENT = new PolymorpheusComponent(LogoComponent); 13 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/classes/samples/accessors.ts: -------------------------------------------------------------------------------- 1 | export const ACCESSORS_SAMPLES = `import { 2 | addAccessors, 3 | getAccessors, 4 | editAccessors, 5 | removeAccessors, 6 | setActiveProject, 7 | saveActiveProject, 8 | } from 'ng-morph'; 9 | 10 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 11 | 12 | addAccessors(getClasses('some/path/file.ts'), [ 13 | { 14 | name: 'setter', 15 | kind: StructureKind.SetAccessor, 16 | }, 17 | ]); 18 | 19 | const declarations = getAccessors(getClasses('some/path/**.ts'), { 20 | name: 'd', 21 | isStatic: true, 22 | }); 23 | 24 | editAccessors(declarations, () => ({ 25 | name: 'anotherName', 26 | })); 27 | 28 | removeAccessors(declarations); 29 | 30 | saveActiveProject(); 31 | `; 32 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/classes/samples/constructors.ts: -------------------------------------------------------------------------------- 1 | export const CONSTRUCTORS_SAMPLES = `import { 2 | addConstructors, 3 | getConstructors, 4 | editConstructors, 5 | removeConstructors, 6 | setActiveProject, 7 | saveActiveProject, 8 | } from 'ng-morph'; 9 | 10 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 11 | 12 | addConstructors(getClasses('some/path/file.ts', { name: 'B' }), { 13 | parameters: [ 14 | { 15 | decorators: [{ name: 'Inject', arguments: ['SomeType'] }], 16 | name: 'param', 17 | type: 'SomeType', 18 | }, 19 | ], 20 | scope: Scope.Protected, 21 | }); 22 | 23 | // Result is: 24 | class B { 25 | protected constructor(@Inject(SomeType) param: SomeType) {} 26 | } 27 | 28 | const declarations = getConstructors(getClasses('some/path/**.ts')); 29 | 30 | editConstructors(declarations, () => ({ 31 | scope: Scope.Protected, 32 | })); 33 | 34 | removeConstructors(declarations); 35 | 36 | saveActiveProject(); 37 | `; 38 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/classes/samples/decorators.ts: -------------------------------------------------------------------------------- 1 | export const DECORATORS_SAMPLES = `import { 2 | addDecorators, 3 | getDecorators, 4 | editDecorators, 5 | removeDecorators, 6 | setActiveProject, 7 | saveActiveProject, 8 | } from 'ng-morph'; 9 | 10 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 11 | 12 | const classes = getClasses('some/path/file.ts'); 13 | const methods = getMethods(classes, { name: 'method' }); 14 | const constructorParams = getParams(getConstructors(classes), { 15 | name: 'param', 16 | }); 17 | const methodParams = getParams(methods); 18 | const properties = getProperties(classes, { name: 'property' }); 19 | const getAccessorss = getAccessors(classes, { name: 'getAccessor' }); 20 | const setAccessors = getAccessors(classes, { name: 'setAccessor' }); 21 | 22 | addDecorators(classes, { 23 | name: 'Component', 24 | arguments: ["{template: ''}"], 25 | }); 26 | 27 | addDecorators(methods, { 28 | name: 'Required', 29 | arguments: [], 30 | }); 31 | 32 | addDecorators(constructorParams, { 33 | name: 'Optional', 34 | arguments: [], 35 | }); 36 | 37 | addDecorators(methodParams, { 38 | name: 'Pure', 39 | arguments: [], 40 | }); 41 | 42 | addDecorators(properties, { 43 | name: 'ContentChild', 44 | arguments: ['SomeComponent'], 45 | }); 46 | 47 | addDecorators(getAccessorss, { 48 | name: 'AnotherDecorator', 49 | arguments: ['SomeComponent', "['string']"], 50 | }); 51 | 52 | addDecorators(setAccessors, { 53 | name: 'SetDecorator', 54 | arguments: ["[1, 3]"], 55 | }); 56 | 57 | const declarations = getAllDecorators('some/path/**.ts', { 58 | name: 'Inject', 59 | }); 60 | 61 | editDecorators(declarations, () => ({ 62 | name: 'Directive', 63 | })); 64 | 65 | removeDecorators(declarations); 66 | 67 | saveActiveProject(); 68 | `; 69 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/classes/samples/methods.ts: -------------------------------------------------------------------------------- 1 | export const METHODS_SAMPLES = `import { 2 | addMethods, 3 | getMethods, 4 | editMethods, 5 | removeMethods, 6 | setActiveProject, 7 | saveActiveProject, 8 | } from 'ng-morph'; 9 | 10 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 11 | 12 | addMethods(getClasses('some/path/file.ts', { name: 'B' }), { 13 | name: 'test', 14 | statements: 'return 0;', 15 | returnType: 'number', 16 | }); 17 | 18 | const declarations = getMethods(getClasses('some/path/**.ts'), { 19 | name: 'd', 20 | isStatic: true, 21 | }); 22 | 23 | editMethods(declarations, ({ isAsync }) => ({ 24 | name: 'b', 25 | isAsync: !isAsync, 26 | })); 27 | 28 | removeMethods(declarations); 29 | 30 | saveActiveProject(); 31 | `; 32 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/classes/samples/properties.ts: -------------------------------------------------------------------------------- 1 | export const PROPERTIES_SAMPLES = `import { 2 | addProperties, 3 | getProperties, 4 | editProperties, 5 | removeProperties, 6 | setActiveProject, 7 | saveActiveProject, 8 | } from 'ng-morph'; 9 | 10 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 11 | 12 | addProperties(getClasses('some/path/file.ts', { name: 'B' }), { 13 | name: 'test', 14 | initializer: '3', 15 | }); 16 | 17 | const declarations = getProperties(getClasses('some/path/**.ts'), { 18 | name: 'd', 19 | isStatic: true, 20 | }); 21 | 22 | editProperties(declarations, () => ({ 23 | name: 'b', 24 | initializer: "'s'", 25 | })); 26 | 27 | removeProperties(declarations); 28 | 29 | saveActiveProject(); 30 | `; 31 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/enums/index.html: -------------------------------------------------------------------------------- 1 | 2 |

You can create, get, edit and remove enums in your files with declarative descriptions and conditions.

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/enums/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const code = `import { 5 | addEnums, 6 | editEnums, 7 | getEnums, 8 | removeEnums, 9 | setActiveProject, 10 | saveActiveProject, 11 | } from 'ng-morph'; 12 | 13 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 14 | 15 | addEnums('some/path/file.ts', [ 16 | { 17 | name: 'Enum', 18 | isConst: true, 19 | members: [{ name: 'First' }, { name: 'second' }], 20 | }, 21 | { 22 | name: 'EmptyEnum', 23 | isExported: true, 24 | }, 25 | ]); 26 | 27 | const declarations = getEnums('some/path/**.ts'); 28 | 29 | editEnums(declarations, () => ({ 30 | name: 'B', 31 | })); 32 | 33 | removeEnums(declarations); 34 | 35 | saveActiveProject(); 36 | `; 37 | 38 | @Component({ 39 | standalone: true, 40 | imports: [TuiAddonDoc], 41 | templateUrl: './index.html', 42 | changeDetection: ChangeDetectionStrategy.OnPush, 43 | }) 44 | export default class EnumsComponent { 45 | protected readonly code = code; 46 | } 47 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/functions/index.html: -------------------------------------------------------------------------------- 1 | 2 |

You can create, get, edit and remove functions in your files with declarative descriptions and conditions.

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/functions/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const code = `import { 5 | addFunctions, 6 | editFunctions, 7 | getFunctions, 8 | removeFunctions, 9 | setActiveProject, 10 | saveActiveProject, 11 | } from 'ng-morph'; 12 | 13 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 14 | 15 | addFunctions('some/**/**.ts', { 16 | isExported: true, 17 | name: 'b', 18 | statements: "return 'b'", 19 | }); 20 | 21 | const declarations = getFunctions('some/path/**.ts'); 22 | 23 | editFunctions(functions, () => ({ 24 | isExported: true, 25 | name: 'b', 26 | statements: "return 'b'", 27 | })); 28 | 29 | removeFunctions(declarations); 30 | 31 | saveActiveProject(); 32 | `; 33 | 34 | @Component({ 35 | standalone: true, 36 | imports: [TuiAddonDoc], 37 | templateUrl: './index.html', 38 | changeDetection: ChangeDetectionStrategy.OnPush, 39 | }) 40 | export default class FunctionsComponent { 41 | protected readonly code = code; 42 | } 43 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/get-bootstrap-function/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Module Application

4 | 5 |

Finds a bootstrap function of Angular application with a path pattern

6 | 7 | 11 |
12 | 13 |
14 |

Standalone Application

15 | 16 |

Finds a bootstrap application function with a path pattern

17 | 18 | 22 |
23 | 24 |
25 |

Add providers to standalone Application

26 | 27 |

28 | To add providers to standalone application you need to use 29 | addProviderToBootstrapApplicationFn 30 | function 31 |

32 | 33 | 37 |
38 |
39 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/get-bootstrap-function/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const bootstrap = `import { 5 | getBootstrapFn, 6 | setActiveProject, 7 | } from 'ng-morph'; 8 | 9 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 10 | 11 | const bootstrapFn = getBootstrapFn('src/main.ts'); 12 | `; 13 | 14 | const bootstrapApplication = `import { 15 | getBootstrapApplicationFn, 16 | setActiveProject, 17 | } from 'ng-morph'; 18 | 19 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 20 | 21 | const bootstrapFn = getBootstrapApplicationFn('src/main.ts'); 22 | `; 23 | 24 | const addProviders = `import { 25 | getBootstrapApplicationFn, 26 | addProviderToBootstrapApplicationFn, 27 | setActiveProject, 28 | } from 'ng-morph'; 29 | 30 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 31 | 32 | const bootstrapFn = getBootstrapApplicationFn('src/main.ts'); 33 | 34 | addProviderToBootstrapApplicationFn(bootstrapFn, 'provideRouter()'); 35 | `; 36 | 37 | @Component({ 38 | standalone: true, 39 | imports: [TuiAddonDoc], 40 | templateUrl: './index.html', 41 | changeDetection: ChangeDetectionStrategy.OnPush, 42 | }) 43 | export default class GetBootstrapFunctionComponent { 44 | protected readonly bootstrap = bootstrap; 45 | protected readonly bootstrapApplication = bootstrapApplication; 46 | protected readonly addProviders = addProviders; 47 | } 48 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/get-main-module/index.html: -------------------------------------------------------------------------------- 1 | 2 |

Finds a main module of Angular application in path pattern

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/get-main-module/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const code = `import { 5 | getMainModule 6 | setActiveProject, 7 | } from 'ng-morph'; 8 | 9 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 10 | 11 | const classDeclaration = getMainModule('src/main.ts'); 12 | `; 13 | 14 | @Component({ 15 | standalone: true, 16 | imports: [TuiAddonDoc], 17 | templateUrl: './index.html', 18 | changeDetection: ChangeDetectionStrategy.OnPush, 19 | }) 20 | export default class GetMainModuleComponent { 21 | protected readonly code = code; 22 | } 23 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/imports-and-exports/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

You can create, get, edit and remove imports in your files with declarative descriptions and conditions.

4 | 5 | 9 |
10 | 11 | 12 |

You can create, get, edit and remove exports in your files with declarative descriptions and conditions.

13 | 14 | 18 |
19 |
20 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/inject-sample/index.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | This is an example of code that migrates your project from 4 | @Inject 5 | constructor injections to 6 | inject 7 | function 8 |

9 | 10 |

11 | You can also try it out on 12 | 18 | Stackblitz 19 | 20 |

21 | 22 | 26 |
27 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/interfaces/index.html: -------------------------------------------------------------------------------- 1 | 2 |

You can create, get, edit and remove interfaces in your files with declarative descriptions and conditions.

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const interfaces = `import { 5 | addInterfaces, 6 | editInterfaces, 7 | getInterfaces, 8 | removeInterfaces, 9 | setActiveProject, 10 | saveActiveProject, 11 | } from 'ng-morph'; 12 | 13 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 14 | 15 | addInterfaces('some/path/file.ts', { 16 | name: 'A', 17 | properties: [{ name: 's', type: 'string' }], 18 | methods: [{ name: 'method', returnType: 'number' }], 19 | }); 20 | 21 | const declarations = getInterfaces('some/path/**.ts'); 22 | 23 | editInterfaces(declarations, () => ({ 24 | name: 'B', 25 | })); 26 | 27 | removeInterfaces(declarations); 28 | 29 | saveActiveProject(); 30 | `; 31 | 32 | @Component({ 33 | standalone: true, 34 | imports: [TuiAddonDoc], 35 | templateUrl: './index.html', 36 | changeDetection: ChangeDetectionStrategy.OnPush, 37 | }) 38 | export default class InterfacesComponent { 39 | protected readonly interfaces = interfaces; 40 | } 41 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/source-files/index.html: -------------------------------------------------------------------------------- 1 | 2 |

You can create, get and move sources files of the project and their paths.

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/source-files/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const code = `import { 5 | createSourceFile, 6 | getSourceFiles, 7 | moveSourceFilePaths, 8 | setActiveProject, 9 | saveActiveProject, 10 | } from 'ng-morph'; 11 | import { dasherize } from '@angular-devkit/core/src/utils/strings'; 12 | 13 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 14 | 15 | createSourceFile('some/path/file.ts', 'const a = "hello";'); 16 | 17 | const sourceFiles = getSourceFiles('some/**/*.ts'); 18 | 19 | // It gets a function that process every file 20 | moveSourceFilePaths(sourceFiles, dasherize); 21 | 22 | saveActiveProject(); 23 | `; 24 | 25 | @Component({ 26 | standalone: true, 27 | imports: [TuiAddonDoc], 28 | templateUrl: './index.html', 29 | changeDetection: ChangeDetectionStrategy.OnPush, 30 | }) 31 | export default class SourceFilesComponent { 32 | protected readonly code = code; 33 | } 34 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/types/index.html: -------------------------------------------------------------------------------- 1 | 2 |

You can create, get, edit and remove types in your files with declarative descriptions and conditions.

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/types/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const types = `import { 5 | addTypeAliases, 6 | editTypeAliases, 7 | getTypeAliases, 8 | removeTypeAliases, 9 | setActiveProject, 10 | saveActiveProject, 11 | } from 'ng-morph'; 12 | 13 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 14 | 15 | addTypeAliases('some/path/file.ts', { 16 | name: 'A', 17 | typeParameters: ['T'], 18 | type: 'T[]', 19 | }); 20 | 21 | const declarations = getTypeAliases('some/path/file.ts'); 22 | 23 | editTypeAliases(declarations, () => ({ 24 | name: 'B', 25 | })); 26 | 27 | removeTypeAliases(declarations); 28 | 29 | saveActiveProject(); 30 | `; 31 | 32 | @Component({ 33 | standalone: true, 34 | imports: [TuiAddonDoc], 35 | templateUrl: './index.html', 36 | changeDetection: ChangeDetectionStrategy.OnPush, 37 | }) 38 | export default class TypesComponent { 39 | protected readonly types = types; 40 | } 41 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/variables/index.html: -------------------------------------------------------------------------------- 1 | 2 |

You can create, get, edit and remove variables in your files with declarative descriptions and conditions.

3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /apps/demo/src/app/pages/variables/index.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {TuiAddonDoc} from '@taiga-ui/addon-doc'; 3 | 4 | const code = `import { 5 | addVariables, 6 | editVariables, 7 | getVariables, 8 | removeVariables, 9 | setActiveProject, 10 | saveActiveProject, 11 | } from 'ng-morph'; 12 | 13 | setActiveProject(createProject(new NgMorphTree(), '/', ['**/*.ts')); 14 | 15 | addVariables('some/path/file.ts', { 16 | declarationKind: VariableDeclarationKind.Const, 17 | declarations: [ 18 | { 19 | name: 'name', 20 | initializer: "'value'", 21 | }, 22 | ], 23 | }); 24 | 25 | const declarations = getVariables('some/path/**.ts'); 26 | 27 | editVariables(declarations, () => ({ 28 | name: 'B', 29 | })); 30 | 31 | removeVariables(declarations); 32 | 33 | saveActiveProject(); 34 | `; 35 | 36 | @Component({ 37 | standalone: true, 38 | selector: 'variables', 39 | imports: [TuiAddonDoc], 40 | templateUrl: './index.html', 41 | changeDetection: ChangeDetectionStrategy.OnPush, 42 | }) 43 | export default class VariablesComponent { 44 | protected readonly code = code; 45 | } 46 | -------------------------------------------------------------------------------- /apps/demo/src/app/routes.ts: -------------------------------------------------------------------------------- 1 | import type {Route} from '@angular/router'; 2 | 3 | export const ROUTES: Route[] = [ 4 | { 5 | path: 'getting-started', 6 | data: {title: 'Getting started'}, 7 | loadComponent: async () => import('./getting-started'), 8 | }, 9 | { 10 | path: 'classes', 11 | data: {title: 'Classes'}, 12 | loadComponent: async () => import('./pages/classes'), 13 | }, 14 | { 15 | path: 'interfaces', 16 | data: {title: 'Interfaces'}, 17 | loadComponent: async () => import('./pages/interfaces'), 18 | }, 19 | { 20 | path: 'variables', 21 | data: {title: 'Variables'}, 22 | loadComponent: async () => import('./pages/variables'), 23 | }, 24 | { 25 | path: 'imports-and-exports', 26 | data: {title: 'Imports and Exports'}, 27 | loadComponent: async () => import('./pages/imports-and-exports'), 28 | }, 29 | { 30 | path: 'enums', 31 | data: {title: 'Enums'}, 32 | loadComponent: async () => import('./pages/enums'), 33 | }, 34 | { 35 | path: 'functions', 36 | data: {title: 'Functions'}, 37 | loadComponent: async () => import('./pages/functions'), 38 | }, 39 | { 40 | path: 'types', 41 | data: {title: 'Types'}, 42 | loadComponent: async () => import('./pages/types'), 43 | }, 44 | { 45 | path: 'get-main-module', 46 | data: {title: 'Get main module'}, 47 | loadComponent: async () => import('./pages/get-main-module'), 48 | }, 49 | { 50 | path: 'get-bootstrap-function', 51 | data: {title: 'Get bootstrap function'}, 52 | loadComponent: async () => import('./pages/get-bootstrap-function'), 53 | }, 54 | { 55 | path: 'source-files', 56 | data: {title: 'Source files'}, 57 | loadComponent: async () => import('./pages/source-files'), 58 | }, 59 | { 60 | path: 'inject-sample', 61 | data: {title: '@Inject -> inject example'}, 62 | loadComponent: async () => import('./pages/inject-sample'), 63 | }, 64 | {path: '**', redirectTo: 'getting-started'}, 65 | ]; 66 | -------------------------------------------------------------------------------- /apps/demo/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/demo/src/assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /apps/demo/src/assets/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/android-chrome-384x384.png -------------------------------------------------------------------------------- /apps/demo/src/assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/demo/src/assets/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/demo/src/assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/favicon-16x16.png -------------------------------------------------------------------------------- /apps/demo/src/assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/favicon-32x32.png -------------------------------------------------------------------------------- /apps/demo/src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/favicon.ico -------------------------------------------------------------------------------- /apps/demo/src/assets/images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /apps/demo/src/assets/images/ng-morph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/images/ng-morph.png -------------------------------------------------------------------------------- /apps/demo/src/assets/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/apps/demo/src/assets/mstile-150x150.png -------------------------------------------------------------------------------- /apps/demo/src/assets/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-384x384.png", 12 | "sizes": "384x384", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /apps/demo/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/demo/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /apps/demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ng-morph 6 | 7 | 11 | 16 | 22 | 28 | 32 | 37 | 41 | 45 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /apps/demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import {importProvidersFrom} from '@angular/core'; 2 | import {bootstrapApplication, BrowserModule} from '@angular/platform-browser'; 3 | import { 4 | BrowserAnimationsModule, 5 | provideAnimations, 6 | } from '@angular/platform-browser/animations'; 7 | import {PreloadAllModules, provideRouter, withPreloading} from '@angular/router'; 8 | import {TUI_DOC_LOGO, TUI_DOC_PAGES} from '@taiga-ui/addon-doc'; 9 | import {NG_EVENT_PLUGINS} from '@taiga-ui/event-plugins'; 10 | 11 | import {AppComponent} from './app/app.component'; 12 | import {LOGO_CONTENT} from './app/logo'; 13 | import {pages} from './app/pages'; 14 | import {ROUTES} from './app/routes'; 15 | 16 | bootstrapApplication(AppComponent, { 17 | providers: [ 18 | importProvidersFrom(BrowserModule, BrowserAnimationsModule), 19 | provideRouter(ROUTES, withPreloading(PreloadAllModules)), 20 | { 21 | provide: TUI_DOC_LOGO, 22 | useValue: LOGO_CONTENT, 23 | }, 24 | { 25 | provide: TUI_DOC_PAGES, 26 | useValue: pages, 27 | }, 28 | provideAnimations(), 29 | NG_EVENT_PLUGINS, 30 | ], 31 | }).catch((e: unknown) => console.error(e)); 32 | -------------------------------------------------------------------------------- /apps/demo/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js'; // Included with Angular CLI. 2 | -------------------------------------------------------------------------------- /apps/demo/src/styles.less: -------------------------------------------------------------------------------- 1 | @import '~highlight.js/styles/github.css'; 2 | 3 | /* You can add global styles to this file, and also import other style files */ 4 | li { 5 | margin-top: 0.5rem; 6 | } 7 | 8 | code { 9 | background: var(--tui-background-base-alt); 10 | color: var(--tui-text-action); 11 | vertical-align: middle; 12 | box-shadow: inset 0 -2px var(--tui-background-neutral-1); 13 | padding: 0.375rem 0.5rem; 14 | font-size: 0.875rem; 15 | border-radius: 0.5rem; 16 | } 17 | 18 | .code-clear { 19 | background: transparent; 20 | box-shadow: none; 21 | } 22 | 23 | tui-doc-page section { 24 | margin-top: 2.5rem; 25 | margin-bottom: 2.5rem; 26 | } 27 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "angularCompilerOptions": { 4 | "strictMetadataEmit": false, 5 | "compilationMode": "full" 6 | }, 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "outDir": "../../dist/out-tsc", 10 | "types": [], 11 | "target": "ES2022", 12 | "useDefineForClassFields": false 13 | }, 14 | "files": ["src/main.ts", "src/polyfills.ts"], 15 | "exclude": ["jest.config.ts"] 16 | } 17 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ], 16 | "compilerOptions": { 17 | "target": "es2020" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { 4 | ...nxPreset, 5 | /* TODO: Update to latest Jest snapshotFormat 6 | * By default Nx has kept the older style of Jest Snapshot formats 7 | * to prevent breaking of any existing tests with snapshots. 8 | * It's recommend you update to the latest format. 9 | * You can do this by removing snapshotFormat property 10 | * and running tests with --update-snapshot flag. 11 | * Example: "nx affected --targets=test --update-snapshot" 12 | * More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format 13 | */ 14 | snapshotFormat: {escapeString: true, printBasicPrototype: true}, 15 | }; 16 | -------------------------------------------------------------------------------- /libs/ng-morph/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [] 3 | } 4 | -------------------------------------------------------------------------------- /libs/ng-morph/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import {pathsToModuleNameMapper} from 'ts-jest'; 3 | import {resolve} from 'node:path'; 4 | 5 | process.env.NODE_OPTIONS = '--experimental-vm-modules'; 6 | 7 | const {compilerOptions} = require(resolve(__dirname, '..', '..', 'tsconfig.json')); 8 | 9 | module.exports = { 10 | displayName: 'ng-morph', 11 | preset: '../../jest.preset.js', 12 | globals: { 13 | 'ts-jest': { 14 | isolatedModules: true, 15 | }, 16 | }, 17 | testEnvironment: 'node', 18 | transform: { 19 | '^.+\\.ts?$': [ 20 | 'ts-jest', 21 | { 22 | tsconfig: '/tsconfig.spec.json', 23 | types: ['node'], 24 | useESM: true, 25 | }, 26 | ], 27 | }, 28 | moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { 29 | prefix: `/../../`, 30 | }), 31 | extensionsToTreatAsEsm: ['.ts'], 32 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 33 | coverageDirectory: '../../coverage/libs/ng-morph', 34 | transformIgnorePatterns: ['node_modules/(?!minimatch/.*)'], 35 | bail: true, 36 | }; 37 | -------------------------------------------------------------------------------- /libs/ng-morph/ng-morph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/ng-morph/9a08482d28ab88ae843b5d1cb59c95103f57875b/libs/ng-morph/ng-morph.png -------------------------------------------------------------------------------- /libs/ng-morph/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-morph", 3 | "version": "4.8.4", 4 | "keywords": [ 5 | "typescript", 6 | "ast", 7 | "mutations", 8 | "angular", 9 | "schematics" 10 | ], 11 | "homepage": "https://taiga-family.github.io/ng-morph/", 12 | "repository": "https://github.com/taiga-family/ng-morph", 13 | "license": "Apache-2.0", 14 | "contributors": [ 15 | "Igor Katsuba ", 16 | "Roman Sedov <79601794011@ya.ru>" 17 | ], 18 | "dependencies": { 19 | "jsonc-parser": "3.3.1", 20 | "minimatch": "10.0.1", 21 | "multimatch": "5.0.0", 22 | "ts-morph": "24.0.0" 23 | }, 24 | "peerDependencies": { 25 | "@angular-devkit/core": ">=16.0.0", 26 | "@angular-devkit/schematics": ">=16.0.0", 27 | "tslib": "^2.8.1" 28 | }, 29 | "authors": [ 30 | "Igor Katsuba " 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /libs/ng-morph/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-morph", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "libs/ng-morph/src", 5 | "projectType": "library", 6 | "targets": { 7 | "lint": { 8 | "executor": "@nx/linter:eslint", 9 | "options": { 10 | "lintFilePatterns": ["libs/{projectName}/**/*.ts"] 11 | }, 12 | "outputs": ["{options.outputFile}"] 13 | }, 14 | "test": { 15 | "executor": "@nx/jest:jest", 16 | "outputs": ["{workspaceRoot}/coverage/{projectName}/ng-morph"], 17 | "options": { 18 | "jestConfig": "libs/{projectName}/jest.config.ts", 19 | "passWithNoTests": true 20 | } 21 | }, 22 | "build": { 23 | "executor": "@nx/js:tsc", 24 | "outputs": ["{options.outputPath}"], 25 | "options": { 26 | "outputPath": "dist/{projectName}", 27 | "tsConfig": "libs/{projectName}/tsconfig.lib.json", 28 | "packageJson": "libs/{projectName}/package.json", 29 | "main": "libs/{projectName}/src/index.ts", 30 | "assets": ["libs/{projectName}/*.md"] 31 | } 32 | }, 33 | "prepublish": { 34 | "executor": "nx:run-commands", 35 | "options": { 36 | "command": "cp ./LICENSE ./README.md ./dist/{projectName}" 37 | } 38 | }, 39 | "publish": { 40 | "executor": "nx:run-commands", 41 | "options": { 42 | "parallel": false, 43 | "commands": [ 44 | "cp ./LICENSE ./README.md ./dist/{projectName}", 45 | "npm publish ./dist/{projectName} --ignore-scripts" 46 | ] 47 | }, 48 | "dependsOn": [ 49 | { 50 | "target": "build", 51 | "params": "ignore", 52 | "dependencies": false 53 | } 54 | ] 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /libs/ng-morph/src/accessors/add-accessors.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassDeclaration, 3 | GetAccessorDeclarationStructure, 4 | SetAccessorDeclarationStructure, 5 | } from 'ts-morph'; 6 | import {Structure} from 'ts-morph'; 7 | 8 | import {coerceArray} from '../utils'; 9 | 10 | export function addAccessors( 11 | classes: ClassDeclaration | ClassDeclaration[], 12 | accessors: 13 | | Array 14 | | GetAccessorDeclarationStructure 15 | | SetAccessorDeclarationStructure, 16 | ): void { 17 | coerceArray(classes).forEach((klass) => { 18 | coerceArray(accessors).forEach((accessor) => { 19 | if (Structure.isGetAccessor(accessor)) { 20 | klass.addGetAccessor(accessor); 21 | } else { 22 | klass.addSetAccessor(accessor); 23 | } 24 | }); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /libs/ng-morph/src/accessors/edit-accessors.ts: -------------------------------------------------------------------------------- 1 | import type {AccessorDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editAccessors = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/accessors/get-accessors.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AccessorDeclaration, 3 | ClassDeclaration, 4 | GetAccessorDeclarationStructure, 5 | SetAccessorDeclarationStructure, 6 | } from 'ts-morph'; 7 | 8 | import type {Query} from '../utils'; 9 | import {arrayFlat, coerceArray, matchQuery} from '../utils'; 10 | 11 | export function getAccessors( 12 | classes: ClassDeclaration | ClassDeclaration[], 13 | query?: Query, 14 | ): AccessorDeclaration[] { 15 | return arrayFlat( 16 | coerceArray(classes).map((klass) => [ 17 | ...klass.getGetAccessors(), 18 | ...klass.getSetAccessors(), 19 | ]), 20 | ).filter((accessor) => matchQuery(accessor.getStructure(), query)); 21 | } 22 | -------------------------------------------------------------------------------- /libs/ng-morph/src/accessors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-accessors'; 2 | export * from './edit-accessors'; 3 | export * from './get-accessors'; 4 | export * from './remove-accessors'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/accessors/remove-accessors.ts: -------------------------------------------------------------------------------- 1 | import type {AccessorDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeAccessors = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/classes/add-classes.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addClasses = getDeclarationCreator({ 7 | kind: StructureKind.Class, 8 | }); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/classes/edit-classes.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editClasses = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/classes/get-classes.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getClasses = getDeclarationGetter((pattern) => 7 | arrayFlat(getSourceFiles(pattern).map((file) => file.getClasses())), 8 | ); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/classes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-classes'; 2 | export * from './edit-classes'; 3 | export * from './get-classes'; 4 | export * from './remove-classes'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/classes/remove-classes.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeClasses = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/constructors/add-constructors.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassDeclaration, 3 | ConstructorDeclarationStructure, 4 | OptionalKind, 5 | } from 'ts-morph'; 6 | 7 | import {coerceArray} from '../utils'; 8 | 9 | export function addConstructors( 10 | classes: ClassDeclaration | ClassDeclaration[], 11 | constructors: 12 | | Array> 13 | | OptionalKind, 14 | ): void { 15 | coerceArray(classes).forEach((klass) => { 16 | klass.addConstructors(coerceArray(constructors)); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /libs/ng-morph/src/constructors/edit-constructors.ts: -------------------------------------------------------------------------------- 1 | import type {ConstructorDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editConstructors = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/constructors/get-constructors.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassDeclaration, 3 | ConstructorDeclaration, 4 | ConstructorDeclarationStructure, 5 | } from 'ts-morph'; 6 | 7 | import type {Query} from '../utils'; 8 | import {arrayFlat, coerceArray, matchQuery} from '../utils'; 9 | 10 | export function getConstructors( 11 | classes: ClassDeclaration | ClassDeclaration[], 12 | query?: Query, 13 | ): ConstructorDeclaration[] { 14 | return arrayFlat(coerceArray(classes).map((klass) => klass.getConstructors())).filter( 15 | (constructor) => 16 | !constructor.isOverload() && matchQuery(constructor.getStructure(), query), 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /libs/ng-morph/src/constructors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-constructors'; 2 | export * from './edit-constructors'; 3 | export * from './get-constructors'; 4 | export * from './remove-constructors'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/constructors/remove-constructors.ts: -------------------------------------------------------------------------------- 1 | import type {ConstructorDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeConstructors = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/decorators/add-decorators.ts: -------------------------------------------------------------------------------- 1 | import type {DecoratableNode, DecoratorStructure, OptionalKind} from 'ts-morph'; 2 | 3 | import {coerceArray} from '../utils'; 4 | 5 | export function addDecorators( 6 | nodes: DecoratableNode | DecoratableNode[], 7 | decorators: 8 | | Array> 9 | | OptionalKind, 10 | ): void { 11 | coerceArray(nodes).forEach((node) => { 12 | node.addDecorators(coerceArray(decorators)); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/decorators/edit-decorators.ts: -------------------------------------------------------------------------------- 1 | import type {Decorator} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editDecorators = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/decorators/get-decorators.ts: -------------------------------------------------------------------------------- 1 | import type {DecoratableNode, Decorator, DecoratorStructure} from 'ts-morph'; 2 | 3 | import {getAccessors} from '../accessors'; 4 | import {getClasses} from '../classes'; 5 | import {getConstructors} from '../constructors'; 6 | import {getMethods} from '../methods'; 7 | import {getParams} from '../params'; 8 | import {getProperties} from '../properties'; 9 | import type {Query} from '../utils'; 10 | import {arrayFlat, coerceArray, getDeclarationGetter, matchQuery} from '../utils'; 11 | 12 | export function getDecorators( 13 | declarations: DecoratableNode | DecoratableNode[], 14 | query?: Query, 15 | ): Decorator[] { 16 | return arrayFlat( 17 | coerceArray(declarations).map((declaration) => declaration.getDecorators()), 18 | ).filter((decorator) => matchQuery(decorator.getStructure(), query)); 19 | } 20 | 21 | export const getAllDecorators = getDeclarationGetter((pattern) => { 22 | const classes = getClasses(pattern); 23 | const methods = getMethods(classes); 24 | const constructors = getConstructors(classes); 25 | const properties = getProperties(classes); 26 | const constructorParams = getParams(constructors); 27 | const methodParams = getParams(methods); 28 | const accessors = getAccessors(classes); 29 | 30 | return arrayFlat( 31 | [classes, methods, properties, constructorParams, methodParams, accessors].map( 32 | (declarations) => getDecorators(declarations), 33 | ), 34 | ); 35 | }); 36 | -------------------------------------------------------------------------------- /libs/ng-morph/src/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-decorators'; 2 | export * from './edit-decorators'; 3 | export * from './get-decorators'; 4 | export * from './remove-decorators'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/decorators/remove-decorators.ts: -------------------------------------------------------------------------------- 1 | import type {Decorator} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeDecorators = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/enums/add-enums.ts: -------------------------------------------------------------------------------- 1 | import type {EnumDeclaration} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addEnums = getDeclarationCreator({ 7 | kind: StructureKind.Enum, 8 | }); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/enums/edit-enums.ts: -------------------------------------------------------------------------------- 1 | import type {EnumDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editEnums = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/enums/get-enums.ts: -------------------------------------------------------------------------------- 1 | import type {EnumDeclaration} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getEnums = getDeclarationGetter((pattern) => 7 | arrayFlat(getSourceFiles(pattern).map((file) => file.getEnums())), 8 | ); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/enums/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-enums'; 2 | export * from './edit-enums'; 3 | export * from './get-enums'; 4 | export * from './remove-enums'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/enums/remove-enums.ts: -------------------------------------------------------------------------------- 1 | import type {EnumDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeEnums = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/exports/add-exports.ts: -------------------------------------------------------------------------------- 1 | import type {ExportDeclaration} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addExports = getDeclarationCreator({ 7 | kind: StructureKind.ExportDeclaration, 8 | }); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/exports/edit-exports.ts: -------------------------------------------------------------------------------- 1 | import type {ExportDeclaration, ExportDeclarationStructure} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editExports = getDeclarationEditor< 6 | ExportDeclaration, 7 | ExportDeclarationStructure & {namedExports: string[]} 8 | >(); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/exports/get-exports.ts: -------------------------------------------------------------------------------- 1 | import type {ExportDeclaration} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getExports = getDeclarationGetter((pattern) => { 7 | const sourceFiles = getSourceFiles(pattern); 8 | 9 | return arrayFlat(sourceFiles.map((file) => file.getExportDeclarations())); 10 | }); 11 | -------------------------------------------------------------------------------- /libs/ng-morph/src/exports/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-exports'; 2 | export * from './edit-exports'; 3 | export * from './get-exports'; 4 | export * from './remove-exports'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/exports/remove-exports.ts: -------------------------------------------------------------------------------- 1 | import type {ExportDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeExports = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/functions/add-functions.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | FunctionDeclaration, 3 | FunctionDeclarationStructure, 4 | OptionalKind, 5 | } from 'ts-morph'; 6 | import {StructureKind} from 'ts-morph'; 7 | 8 | import {getDeclarationCreator} from '../utils'; 9 | 10 | export const addFunctions = getDeclarationCreator< 11 | FunctionDeclaration, 12 | OptionalKind 13 | >({kind: StructureKind.Function}); 14 | -------------------------------------------------------------------------------- /libs/ng-morph/src/functions/edit-functions.ts: -------------------------------------------------------------------------------- 1 | import type {FunctionDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editFunctions = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/functions/get-functions.ts: -------------------------------------------------------------------------------- 1 | import type {FunctionDeclaration, FunctionDeclarationStructure} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getFunctions = getDeclarationGetter< 7 | FunctionDeclaration, 8 | FunctionDeclarationStructure 9 | >((pattern) => { 10 | const files = getSourceFiles(pattern); 11 | 12 | return arrayFlat(files.map((file) => file.getFunctions())).filter( 13 | (fn) => !fn.isOverload(), 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /libs/ng-morph/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-functions'; 2 | export * from './edit-functions'; 3 | export * from './get-functions'; 4 | export * from './remove-functions'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/functions/remove-functions.ts: -------------------------------------------------------------------------------- 1 | import type {FunctionDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeFunctions = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/imports/add-imports.ts: -------------------------------------------------------------------------------- 1 | import type {ImportDeclaration} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addImports = getDeclarationCreator( 7 | {kind: StructureKind.ImportDeclaration}, 8 | {position: 0}, 9 | ); 10 | -------------------------------------------------------------------------------- /libs/ng-morph/src/imports/edit-imports.ts: -------------------------------------------------------------------------------- 1 | import type {ImportDeclaration, ImportDeclarationStructure} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editImports = getDeclarationEditor< 6 | ImportDeclaration, 7 | ImportDeclarationStructure & {namedImports: string[]} 8 | >(); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/imports/get-imports.ts: -------------------------------------------------------------------------------- 1 | import type {ImportDeclaration} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getImports = getDeclarationGetter((pattern) => { 7 | const sourceFiles = getSourceFiles(pattern); 8 | 9 | return arrayFlat(sourceFiles.map((file) => file.getImportDeclarations())); 10 | }); 11 | -------------------------------------------------------------------------------- /libs/ng-morph/src/imports/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-imports'; 2 | export * from './edit-imports'; 3 | export * from './get-imports'; 4 | export * from './remove-imports'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/imports/remove-imports.ts: -------------------------------------------------------------------------------- 1 | import type {ImportDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeImports = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './accessors'; 2 | export * from './classes'; 3 | export * from './constructors'; 4 | export * from './decorators'; 5 | export * from './enums'; 6 | export * from './exports'; 7 | export * from './functions'; 8 | export * from './imports'; 9 | export * from './interfaces'; 10 | export * from './json'; 11 | export * from './methods'; 12 | export * from './ng'; 13 | export * from './params'; 14 | export * from './project'; 15 | export * from './properties'; 16 | export * from './source-file'; 17 | export * from './type-aliases'; 18 | export * from './utils'; 19 | export * from './variables'; 20 | export * from 'ts-morph'; 21 | -------------------------------------------------------------------------------- /libs/ng-morph/src/interfaces/add-interfaces.ts: -------------------------------------------------------------------------------- 1 | import type {InterfaceDeclaration} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addInterfaces = getDeclarationCreator({ 7 | kind: StructureKind.Interface, 8 | }); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/interfaces/edit-interfaces.ts: -------------------------------------------------------------------------------- 1 | import type {InterfaceDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editInterfaces = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/interfaces/get-interfaces.ts: -------------------------------------------------------------------------------- 1 | import type {InterfaceDeclaration} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getInterfaces = getDeclarationGetter((pattern) => 7 | arrayFlat(getSourceFiles(pattern).map((file) => file.getInterfaces())), 8 | ); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-interfaces'; 2 | export * from './edit-interfaces'; 3 | export * from './get-interfaces'; 4 | export * from './remove-interfaces'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/interfaces/remove-interfaces.ts: -------------------------------------------------------------------------------- 1 | import type {InterfaceDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeInterfaces = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/json/consts.ts: -------------------------------------------------------------------------------- 1 | export const ANGULAR_PATH = 'angular.json'; 2 | export const NX_PATH = 'nx.json'; 3 | export const PACKAGE_PATH = 'package.json'; 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/json/get-project-targets.ts: -------------------------------------------------------------------------------- 1 | import type {Tree} from '@angular-devkit/schematics'; 2 | import type {WorkspaceProject} from '@schematics/angular/utility/workspace-models'; 3 | 4 | import {ANGULAR_PATH} from './consts'; 5 | import {JSONFile} from './json-file'; 6 | 7 | export function getProjectTargets( 8 | host: Tree, 9 | angularJsonPath: string = ANGULAR_PATH, 10 | ): Map { 11 | const file = new JSONFile(host, angularJsonPath); 12 | 13 | const projects = file.get(['projects']); 14 | 15 | if (projects) { 16 | return new Map(Object.entries(projects) as Array<[string, any]>); 17 | } 18 | 19 | return new Map(); 20 | } 21 | 22 | export function getProjectTarget( 23 | host: Tree, 24 | name: string, 25 | angularJsonPath: string = ANGULAR_PATH, 26 | ): WorkspaceProject | null { 27 | const file = new JSONFile(host, angularJsonPath); 28 | 29 | return (file.get(['projects', name]) as any) ?? null; 30 | } 31 | -------------------------------------------------------------------------------- /libs/ng-morph/src/json/index.ts: -------------------------------------------------------------------------------- 1 | export * from './consts'; 2 | export * from './dependencies'; 3 | export * from './get-project-targets'; 4 | export * from './insertion-index'; 5 | export * from './json-file'; 6 | export * from './json-file-content'; 7 | export * from './json-path'; 8 | -------------------------------------------------------------------------------- /libs/ng-morph/src/json/insertion-index.ts: -------------------------------------------------------------------------------- 1 | export type InsertionIndex = (properties: string[]) => number; 2 | -------------------------------------------------------------------------------- /libs/ng-morph/src/json/json-file.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google Inc. All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | 9 | import type {JsonValue} from '@angular-devkit/core'; 10 | import type {Tree} from '@angular-devkit/schematics'; 11 | import type {Node} from 'jsonc-parser'; 12 | 13 | import type {InsertionIndex} from './insertion-index'; 14 | import {JSONFileContent} from './json-file-content'; 15 | import type {JSONPath} from './json-path'; 16 | 17 | export class JSONFile extends JSONFileContent { 18 | private readonly host: Tree; 19 | private readonly path: string; 20 | 21 | constructor(host: Tree, path: string) { 22 | const buffer = host.read(path); 23 | 24 | if (buffer) { 25 | super(buffer.toString()); 26 | } else { 27 | throw new Error(`Could not read '${path}'.`); 28 | } 29 | 30 | this.host = host; 31 | this.path = path; 32 | } 33 | 34 | public override modify( 35 | jsonPath: JSONPath, 36 | value: JsonValue | undefined, 37 | insertInOrder?: InsertionIndex | false, 38 | ): void { 39 | super.modify(jsonPath, value, insertInOrder); 40 | this.host.overwrite(this.path, this.content); 41 | } 42 | 43 | protected override jsonAst(): Node | undefined { 44 | try { 45 | return super.jsonAst(); 46 | } catch (e: unknown) { 47 | throw new Error(`[${this.path}] ${(e as Error | undefined)?.message}`); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /libs/ng-morph/src/json/json-path.ts: -------------------------------------------------------------------------------- 1 | export type JSONPath = Array; 2 | -------------------------------------------------------------------------------- /libs/ng-morph/src/methods/add-methods.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration, MethodDeclarationStructure, OptionalKind} from 'ts-morph'; 2 | 3 | import {coerceArray} from '../utils'; 4 | 5 | export function addMethods( 6 | classes: ClassDeclaration | ClassDeclaration[], 7 | methods: 8 | | Array> 9 | | OptionalKind, 10 | ): void { 11 | coerceArray(classes).forEach((klass) => { 12 | klass.addMethods(coerceArray(methods)); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/methods/edit-methods.ts: -------------------------------------------------------------------------------- 1 | import type {MethodDeclaration, MethodDeclarationStructure} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editMethods = getDeclarationEditor< 6 | MethodDeclaration, 7 | MethodDeclarationStructure 8 | >(); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/methods/get-methods.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassDeclaration, 3 | MethodDeclaration, 4 | MethodDeclarationStructure, 5 | } from 'ts-morph'; 6 | 7 | import type {Query} from '../utils'; 8 | import {arrayFlat, coerceArray, matchQuery} from '../utils'; 9 | 10 | export function getMethods( 11 | classes: ClassDeclaration | ClassDeclaration[], 12 | query?: Query, 13 | ): MethodDeclaration[] { 14 | return arrayFlat(coerceArray(classes).map((klass) => klass.getMethods())).filter( 15 | (method) => !method.isOverload() && matchQuery(method.getStructure(), query), 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /libs/ng-morph/src/methods/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-methods'; 2 | export * from './edit-methods'; 3 | export * from './get-methods'; 4 | export * from './remove-methods'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/methods/remove-methods.ts: -------------------------------------------------------------------------------- 1 | import type {MethodDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeMethods = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/bootstrap/add-provider-to-bootstrap-application-fn.ts: -------------------------------------------------------------------------------- 1 | import type {CallExpression, Identifier, ObjectLiteralExpression} from 'ts-morph'; 2 | import {Node, SyntaxKind} from 'ts-morph'; 3 | 4 | import {pushToObjectLiteralArrayProperty} from '../helpers/push-to-object-literal-array-property'; 5 | 6 | export function addProviderToBootstrapApplicationFn( 7 | callExpression: CallExpression, 8 | provider: string, 9 | {unique = false}: {unique?: boolean} = {}, 10 | ): void { 11 | const [, options = callExpression.addArgument('{providers: []}')] = 12 | callExpression.getArguments(); 13 | 14 | if (!Node.isIdentifier(options) && !Node.isObjectLiteralExpression(options)) { 15 | return; 16 | } 17 | 18 | const expression = getOptionsObject(options); 19 | 20 | if (expression) { 21 | pushToObjectLiteralArrayProperty(expression, 'providers', provider, {unique}); 22 | } 23 | } 24 | 25 | function getOptionsObject( 26 | options: Identifier | ObjectLiteralExpression, 27 | ): ObjectLiteralExpression | undefined { 28 | if (Node.isObjectLiteralExpression(options)) { 29 | return options; 30 | } 31 | 32 | const definition = options.getDefinitionNodes()[0]; 33 | 34 | return definition?.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0]; 35 | } 36 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/bootstrap/get-bootstrap-application-fn.ts: -------------------------------------------------------------------------------- 1 | import type {CallExpression} from 'ts-morph'; 2 | import {Identifier, Node, SyntaxKind} from 'ts-morph'; 3 | 4 | import {getImports} from '../../imports'; 5 | 6 | export function getBootstrapApplicationFn( 7 | mainFilePath: string, 8 | ): CallExpression | undefined { 9 | const [bootstrapApplicationImport] = getImports(mainFilePath, { 10 | moduleSpecifier: '@angular/platform-browser', 11 | }); 12 | 13 | const namedImport = bootstrapApplicationImport 14 | ?.getNamedImports() 15 | .find((imp) => imp.getName() === 'bootstrapApplication'); 16 | 17 | const nameNode = namedImport?.getNameNode(); 18 | 19 | if (nameNode instanceof Identifier) { 20 | return nameNode 21 | .findReferencesAsNodes() 22 | .find((ref) => Node.isCallExpression(ref.getParent())) 23 | ?.getParentIfKind(SyntaxKind.CallExpression); 24 | } 25 | 26 | return undefined; 27 | } 28 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/bootstrap/get-bootstrap-fn.ts: -------------------------------------------------------------------------------- 1 | import type {CallExpression} from 'ts-morph'; 2 | import {Identifier, Node, SyntaxKind} from 'ts-morph'; 3 | 4 | import {getImports} from '../../imports'; 5 | 6 | export function getBootstrapFn(mainFilePath: string): CallExpression | undefined { 7 | const [platformBrowserImport] = getImports(mainFilePath, { 8 | moduleSpecifier: '@angular/platform-browser-dynamic', 9 | }); 10 | 11 | const namedImport = platformBrowserImport 12 | ?.getNamedImports() 13 | .find((imp) => imp.getName() === 'platformBrowserDynamic'); 14 | 15 | const nameNode = namedImport?.getNameNode(); 16 | 17 | if (nameNode instanceof Identifier) { 18 | return nameNode 19 | .findReferencesAsNodes() 20 | .find((ref) => Node.isCallExpression(ref.getParent())) 21 | ?.getParentIfKind(SyntaxKind.CallExpression) 22 | ?.getParentIfKind(SyntaxKind.PropertyAccessExpression) 23 | ?.getParentIfKind(SyntaxKind.CallExpression); 24 | } 25 | 26 | return undefined; 27 | } 28 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/bootstrap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-provider-to-bootstrap-application-fn'; 2 | export * from './get-bootstrap-application-fn'; 3 | export * from './get-bootstrap-fn'; 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/component/add-import-to-component.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addImportToComponent( 6 | classDeclaration: ClassDeclaration, 7 | importName: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'Component', 'imports', importName, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/component/add-provider-to-component.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addProviderToComponent( 6 | classDeclaration: ClassDeclaration, 7 | provider: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'Component', 'providers', provider, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/component/add-style-url-to-component.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addStyleUrlToComponent( 6 | classDeclaration: ClassDeclaration, 7 | styleUrl: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'Component', 'styleUrls', styleUrl, { 11 | unique, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-import-to-component'; 2 | export * from './add-provider-to-component'; 3 | export * from './add-style-url-to-component'; 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/directive/add-provider-to-directive.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addProviderToDirective( 6 | classDeclaration: ClassDeclaration, 7 | provider: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'Directive', 'providers', provider, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/directive/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-provider-to-directive'; 2 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/get-main-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration, Identifier} from 'ts-morph'; 2 | 3 | import {getBootstrapFn} from '../bootstrap'; 4 | 5 | export function getMainModule(mainFilePath: string): ClassDeclaration | undefined { 6 | const bootstrapFn = getBootstrapFn(mainFilePath); 7 | 8 | const [mainModuleIdentifier] = 9 | (bootstrapFn?.getArguments?.() as [Identifier] | undefined) || []; 10 | 11 | const [mainModuleClass] = 12 | (mainModuleIdentifier?.getDefinitionNodes() as [ClassDeclaration] | undefined) || 13 | []; 14 | 15 | return mainModuleClass; 16 | } 17 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-main-module'; 2 | export * from './is-standalone-component'; 3 | export * from './ng-component'; 4 | export * from './ng-module'; 5 | export * from './push-to-decorator-array-property'; 6 | export * from './push-to-object-literal-array-property'; 7 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/is-standalone-component.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | import {Node} from 'ts-morph'; 3 | 4 | export function isStandaloneComponent(component: ClassDeclaration): boolean { 5 | const decorator = component.getDecorator('Component'); 6 | 7 | if (!decorator) { 8 | return false; 9 | } 10 | 11 | const [metadata] = decorator.getArguments(); 12 | 13 | if (!Node.isObjectLiteralExpression(metadata)) { 14 | return false; 15 | } 16 | 17 | const property = metadata.getProperty('standalone'); 18 | 19 | if (!Node.isPropertyAssignment(property)) { 20 | return false; 21 | } 22 | 23 | return property.getInitializer()?.getText() === 'true'; 24 | } 25 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/ng-component.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {getClasses} from '../../classes'; 4 | import type {Pattern, Query, StructureType} from '../../utils'; 5 | 6 | export function getNgComponents( 7 | pattern: Pattern, 8 | query?: Query, 'kind'>>, 9 | ): ClassDeclaration[] { 10 | return getClasses(pattern, query).filter( 11 | (declaration) => !!declaration.getDecorator('Component'), 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {getClasses} from '../../classes'; 4 | import {getImports} from '../../imports'; 5 | import type {Pattern, Query, StructureType} from '../../utils'; 6 | 7 | export function getNgModules( 8 | pattern: Pattern, 9 | query?: Query, 'kind'>>, 10 | ): ClassDeclaration[] { 11 | return getClasses(pattern, query).filter( 12 | (declaration) => !!declaration.getDecorator('NgModule'), 13 | ); 14 | } 15 | 16 | /** 17 | * Find NgModule where the component was declared. 18 | */ 19 | export function findNgModule( 20 | ngComponent: ClassDeclaration, 21 | pattern: Pattern, 22 | ): ClassDeclaration | null { 23 | const allNgModules = getNgModules(pattern); 24 | 25 | return ( 26 | allNgModules.find((module) => { 27 | const moduleFile = module.getSourceFile(); 28 | const imports = getImports(moduleFile.getFilePath(), { 29 | namedImports: ngComponent.getName(), 30 | }); 31 | 32 | return imports.some( 33 | (i) => i.getModuleSpecifierSourceFile() === ngComponent.getSourceFile(), 34 | ); 35 | }) || null 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/push-to-decorator-array-property.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | import {Node} from 'ts-morph'; 3 | 4 | import {getDecorators} from '../../decorators'; 5 | import {pushToObjectLiteralArrayProperty} from './push-to-object-literal-array-property'; 6 | 7 | // TODO: investigate how to handle consts in descriptors that don't accept array of array type, like styleUrls 8 | export function pushToDecoratorArrayProperty( 9 | classDeclaration: ClassDeclaration, 10 | decoratorName: string, 11 | propertyName: string, 12 | initializer: string, 13 | { 14 | unique = false, 15 | forceToArray = false, 16 | }: {unique?: boolean; forceToArray?: boolean} = {}, 17 | ): void { 18 | const [decorator] = getDecorators(classDeclaration, { 19 | name: decoratorName, 20 | }); 21 | 22 | const [metadata = decorator?.addArgument(`{${propertyName}: []}`)] = 23 | decorator?.getArguments() || []; 24 | 25 | if (!Node.isObjectLiteralExpression(metadata)) { 26 | return; 27 | } 28 | 29 | pushToObjectLiteralArrayProperty(metadata, propertyName, initializer, { 30 | unique, 31 | forceToArray, 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/helpers/push-to-object-literal-array-property.ts: -------------------------------------------------------------------------------- 1 | import type {ObjectLiteralExpression} from 'ts-morph'; 2 | import {Node} from 'ts-morph'; 3 | 4 | export function pushToObjectLiteralArrayProperty( 5 | objectLiteral: ObjectLiteralExpression, 6 | propertyName: string, 7 | initializer: string, 8 | { 9 | unique = false, 10 | forceToArray = false, 11 | }: {unique?: boolean; forceToArray?: boolean} = {}, 12 | ): void { 13 | const property = 14 | objectLiteral.getProperty(propertyName) ?? 15 | objectLiteral.addProperty(`${propertyName}: []`); 16 | 17 | if (!Node.isPropertyAssignment(property)) { 18 | return; 19 | } 20 | 21 | if (forceToArray && !Node.isArrayLiteralExpression(property.getInitializer())) { 22 | property.setInitializer(`[${property.getInitializer()?.getText()}]`); 23 | } 24 | 25 | const importsInitializer = property.getInitializer(); 26 | 27 | if (!Node.isArrayLiteralExpression(importsInitializer)) { 28 | return; 29 | } 30 | 31 | if ( 32 | unique && 33 | importsInitializer 34 | .getElements() 35 | .some((element) => element.getText() === initializer) 36 | ) { 37 | return; 38 | } 39 | 40 | importsInitializer.addElement(initializer); 41 | } 42 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bootstrap'; 2 | export * from './component'; 3 | export * from './directive'; 4 | export * from './helpers'; 5 | export * from './helpers/is-standalone-component'; 6 | export * from './helpers/ng-component'; 7 | export * from './helpers/ng-module'; 8 | export * from './module'; 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-bootstrap-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addBootstrapToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | component: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'NgModule', 'bootstrap', component, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-declaration-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addDeclarationToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | declaration: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty( 11 | classDeclaration, 12 | 'NgModule', 13 | 'declarations', 14 | declaration, 15 | { 16 | unique, 17 | forceToArray: true, 18 | }, 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-entry-component-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addEntryComponentToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | component: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty( 11 | classDeclaration, 12 | 'NgModule', 13 | 'entryComponents', 14 | component, 15 | {unique, forceToArray: true}, 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-export-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addExportToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | exportName: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'NgModule', 'exports', exportName, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-import-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addImportToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | moduleName: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'NgModule', 'imports', moduleName, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-provider-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addProviderToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | provider: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'NgModule', 'providers', provider, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/add-schema-to-ng-module.ts: -------------------------------------------------------------------------------- 1 | import type {ClassDeclaration} from 'ts-morph'; 2 | 3 | import {pushToDecoratorArrayProperty} from '../helpers'; 4 | 5 | export function addSchemaToNgModule( 6 | classDeclaration: ClassDeclaration, 7 | schema: string, 8 | {unique = false}: {unique?: boolean} = {}, 9 | ): void { 10 | pushToDecoratorArrayProperty(classDeclaration, 'NgModule', 'schemas', schema, { 11 | unique, 12 | forceToArray: true, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/ng/module/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-bootstrap-to-ng-module'; 2 | export * from './add-declaration-to-ng-module'; 3 | export * from './add-entry-component-to-ng-module'; 4 | export * from './add-export-to-ng-module'; 5 | export * from './add-import-to-ng-module'; 6 | export * from './add-provider-to-ng-module'; 7 | export * from './add-schema-to-ng-module'; 8 | -------------------------------------------------------------------------------- /libs/ng-morph/src/params/add-params.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | FunctionLikeDeclaration, 3 | OptionalKind, 4 | ParameterDeclarationStructure, 5 | } from 'ts-morph'; 6 | 7 | import {coerceArray} from '../utils'; 8 | 9 | export function addParams( 10 | functionsLike: FunctionLikeDeclaration | FunctionLikeDeclaration[], 11 | params: 12 | | Array> 13 | | OptionalKind, 14 | ): void { 15 | coerceArray(functionsLike).forEach((functionLike) => { 16 | functionLike.addParameters(coerceArray(params)); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /libs/ng-morph/src/params/edit-params.ts: -------------------------------------------------------------------------------- 1 | import type {ParameterDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editParams = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/params/get-params.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | FunctionLikeDeclaration, 3 | ParameterDeclaration, 4 | ParameterDeclarationStructure, 5 | } from 'ts-morph'; 6 | 7 | import type {Query} from '../utils'; 8 | import {arrayFlat, coerceArray, matchQuery} from '../utils'; 9 | 10 | export function getParams( 11 | functionsLike: FunctionLikeDeclaration | FunctionLikeDeclaration[], 12 | query?: Query, 13 | ): ParameterDeclaration[] { 14 | return arrayFlat( 15 | coerceArray(functionsLike).map((functionLike) => functionLike.getParameters()), 16 | ).filter((param) => matchQuery(param.getStructure(), query)); 17 | } 18 | -------------------------------------------------------------------------------- /libs/ng-morph/src/params/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-params'; 2 | export * from './edit-params'; 3 | export * from './get-params'; 4 | export * from './remove-params'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/params/remove-params.ts: -------------------------------------------------------------------------------- 1 | import type {ParameterDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeParams = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/create-project.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'node:path'; 2 | 3 | import type {Tree} from '@angular-devkit/schematics'; 4 | 5 | import type {Pattern} from '../utils'; 6 | import {coerceArray} from '../utils'; 7 | import {NgCliProject} from './ng-cli-project'; 8 | 9 | export function createProject( 10 | host: Tree, 11 | rootPath = '/', 12 | pattern: Pattern = ['**/*.ts'], 13 | ): NgCliProject { 14 | const project = new NgCliProject({host}); 15 | 16 | project.addSourceFilesAtPaths( 17 | coerceArray(pattern).map((glob) => 18 | project.getFileSystem().fs.resolve(join(rootPath, glob)), 19 | ), 20 | ); 21 | 22 | return project; 23 | } 24 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-project'; 2 | export * from './devkit-file-system'; 3 | export * from './file-system'; 4 | export * from './ng-cli-project'; 5 | export * from './ng-cli-project-options'; 6 | export * from './ng-morph-tree'; 7 | export * from './project'; 8 | export * from './save-project'; 9 | export * from './update-recorder'; 10 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/ng-cli-project-options.ts: -------------------------------------------------------------------------------- 1 | import type {Tree} from '@angular-devkit/schematics'; 2 | import type {ProjectOptions} from 'ts-morph'; 3 | 4 | export interface NgCliProjectOptions extends Omit { 5 | host: Tree; 6 | } 7 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/ng-cli-project.ts: -------------------------------------------------------------------------------- 1 | import {Project} from 'ts-morph'; 2 | 3 | import {DevkitFileSystem} from './devkit-file-system'; 4 | import {NgCliFileSystem} from './file-system'; 5 | import type {NgCliProjectOptions} from './ng-cli-project-options'; 6 | import {NgMorphTree} from './ng-morph-tree'; 7 | 8 | export class NgCliProject extends Project { 9 | constructor({host, ...options}: NgCliProjectOptions) { 10 | super({ 11 | ...options, 12 | fileSystem: new NgCliFileSystem(new DevkitFileSystem(host)), 13 | }); 14 | } 15 | 16 | public override getFileSystem(): NgCliFileSystem { 17 | return super.getFileSystem() as NgCliFileSystem; 18 | } 19 | 20 | public override async save(): Promise { 21 | await super.save(); 22 | await this.trySaveTree(); 23 | } 24 | 25 | public override saveSync(): void { 26 | super.saveSync(); 27 | void this.trySaveTree(); 28 | } 29 | 30 | private async trySaveTree(): Promise { 31 | const tree = this.getFileSystem().fs.tree; 32 | 33 | if (tree instanceof NgMorphTree) { 34 | await tree.commitChanges(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/ng-morph-tree.ts: -------------------------------------------------------------------------------- 1 | import {normalize} from '@angular-devkit/core'; 2 | import {NodeJsSyncHost} from '@angular-devkit/core/node'; 3 | import {ScopedHost} from '@angular-devkit/core/src/virtual-fs/host/scoped'; 4 | import {HostSink, HostTree} from '@angular-devkit/schematics'; 5 | import {firstValueFrom} from 'rxjs'; 6 | 7 | export class NgMorphTree extends HostTree { 8 | private readonly hostSink: HostSink; 9 | 10 | constructor(root: string = process.cwd()) { 11 | const host = new ScopedHost(new NodeJsSyncHost(), normalize(root)); 12 | 13 | super(host); 14 | 15 | this.hostSink = new HostSink(host as any); 16 | } 17 | 18 | public async commitChanges(): Promise { 19 | return firstValueFrom(this.hostSink.commit(this)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/project.ts: -------------------------------------------------------------------------------- 1 | import type {NgCliProject} from './ng-cli-project'; 2 | 3 | let prevProject: NgCliProject | null = null; 4 | 5 | export function setActiveProject(project: NgCliProject | null): NgCliProject | null { 6 | const prev = prevProject; 7 | 8 | prevProject = project; 9 | 10 | return prev; 11 | } 12 | 13 | export function getActiveProject(): NgCliProject | null { 14 | return prevProject; 15 | } 16 | 17 | export function resetActiveProject(): NgCliProject | null { 18 | return setActiveProject(null); 19 | } 20 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/save-project.ts: -------------------------------------------------------------------------------- 1 | import {getActiveProject} from './project'; 2 | 3 | export async function saveActiveProjectAsync(): Promise { 4 | await getActiveProject()?.save(); 5 | } 6 | 7 | export function saveActiveProject(): void { 8 | getActiveProject()?.saveSync(); 9 | } 10 | -------------------------------------------------------------------------------- /libs/ng-morph/src/project/update-recorder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google LLC All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | 9 | /** Update recorder that can be used to apply changes to a source file. */ 10 | export interface UpdateRecorder { 11 | insertLeft(index: number, content: string): UpdateRecorder; 12 | 13 | insertRight(index: number, content: string): UpdateRecorder; 14 | 15 | remove(index: number, length: number): UpdateRecorder; 16 | } 17 | -------------------------------------------------------------------------------- /libs/ng-morph/src/properties/add-properties.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassDeclaration, 3 | OptionalKind, 4 | PropertyDeclarationStructure, 5 | } from 'ts-morph'; 6 | 7 | import {coerceArray} from '../utils'; 8 | 9 | export function addProperties( 10 | classes: ClassDeclaration | ClassDeclaration[], 11 | properties: 12 | | Array> 13 | | OptionalKind, 14 | ): void { 15 | coerceArray(classes).forEach((klass) => { 16 | klass.addProperties(coerceArray(properties)); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /libs/ng-morph/src/properties/edit-properties.ts: -------------------------------------------------------------------------------- 1 | import type {PropertyDeclaration, PropertyDeclarationStructure} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editProperties = getDeclarationEditor< 6 | PropertyDeclaration, 7 | PropertyDeclarationStructure 8 | >(); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/properties/get-properties.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassDeclaration, 3 | PropertyDeclaration, 4 | PropertyDeclarationStructure, 5 | } from 'ts-morph'; 6 | 7 | import type {Query} from '../utils'; 8 | import {arrayFlat, coerceArray, matchQuery} from '../utils'; 9 | 10 | export function getProperties( 11 | classes: T | T[], 12 | query?: Query, 13 | ): PropertyDeclaration[] { 14 | return arrayFlat(coerceArray(classes).map((klass) => klass.getProperties())).filter( 15 | (method) => matchQuery(method.getStructure(), query), 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /libs/ng-morph/src/properties/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-properties'; 2 | export * from './edit-properties'; 3 | export * from './get-properties'; 4 | export * from './remove-properties'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/properties/remove-properties.ts: -------------------------------------------------------------------------------- 1 | import type {PropertyDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeProperties = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/source-file/create-source-file.ts: -------------------------------------------------------------------------------- 1 | import type {SourceFile} from 'ts-morph'; 2 | 3 | import {getActiveProject} from '../project'; 4 | 5 | export function createSourceFile( 6 | filePath: string, 7 | content?: string, 8 | {overwrite = false}: {overwrite?: boolean} = {}, 9 | ): SourceFile | undefined { 10 | return getActiveProject()?.createSourceFile(filePath, content, {overwrite}); 11 | } 12 | -------------------------------------------------------------------------------- /libs/ng-morph/src/source-file/get-source-files.ts: -------------------------------------------------------------------------------- 1 | import type {SourceFile} from 'ts-morph'; 2 | 3 | import {getActiveProject} from '../project'; 4 | 5 | export function getSourceFiles(pattern?: string[] | string): SourceFile[] { 6 | return getActiveProject()?.getSourceFiles(pattern as string) || []; 7 | } 8 | 9 | export function getSourceFile(filePath: string): SourceFile | null { 10 | return getActiveProject()?.getSourceFile(filePath) ?? null; 11 | } 12 | -------------------------------------------------------------------------------- /libs/ng-morph/src/source-file/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-source-file'; 2 | export * from './get-source-files'; 3 | export * from './move-source-file-paths'; 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/source-file/move-source-file-paths.ts: -------------------------------------------------------------------------------- 1 | import type {SourceFile} from 'ts-morph'; 2 | 3 | export function moveSourceFilePaths( 4 | files: SourceFile[], 5 | rename: (path: string) => string, 6 | ): void { 7 | files.forEach((file) => { 8 | file.move(rename(file.getFilePath())); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /libs/ng-morph/src/type-aliases/add-type-aliases.ts: -------------------------------------------------------------------------------- 1 | import type {TypeAliasDeclaration} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addTypeAliases = getDeclarationCreator({ 7 | kind: StructureKind.TypeAlias, 8 | }); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/type-aliases/edit-type-aliases.ts: -------------------------------------------------------------------------------- 1 | import type {TypeAliasDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editTypeAliases = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/type-aliases/get-type-aliases.ts: -------------------------------------------------------------------------------- 1 | import type {TypeAliasDeclaration} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getTypeAliases = getDeclarationGetter((pattern) => 7 | arrayFlat(getSourceFiles(pattern).map((file) => file.getTypeAliases())), 8 | ); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/type-aliases/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-type-aliases'; 2 | export * from './edit-type-aliases'; 3 | export * from './get-type-aliases'; 4 | export * from './remove-type-aliases'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/type-aliases/remove-type-aliases.ts: -------------------------------------------------------------------------------- 1 | import type {TypeAliasDeclaration} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeTypeAliases = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/array-flat.ts: -------------------------------------------------------------------------------- 1 | export function arrayFlat(array: T[][]): T[] { 2 | return array.reduce((agr, current) => agr.concat(current), []); 3 | } 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/coerce-array.ts: -------------------------------------------------------------------------------- 1 | export function coerceArray(value: T | T[]): T[] { 2 | return Array.isArray(value) ? value : [value]; 3 | } 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/colored-log.ts: -------------------------------------------------------------------------------- 1 | export function processLog(message: string): void { 2 | console.info('\x1B[36m%s\x1B[0m', message); 3 | } 4 | 5 | export function errorLog(message: string): void { 6 | console.info('\x1B[31m%s\x1B[0m', message); 7 | } 8 | 9 | export function successLog(message: string): void { 10 | console.info('\x1B[32m%s\x1B[0m', message); 11 | } 12 | 13 | export function infoLog(message: string): void { 14 | console.info('\x1B[34m%s\x1B[0m', message); 15 | } 16 | 17 | export function titleLog(message: string): void { 18 | console.info('\x1B[35m', message); 19 | } 20 | 21 | export const SMALL_TAB_SYMBOL = ' '; // @note: if you use \t then we have big gaps 22 | export const START_SYMBOL = '🚀'; 23 | export const FINISH_SYMBOL = '🏆'; 24 | export const REPLACE_SYMBOL = '⚡️'; 25 | export const PROCESSING_SYMBOL = '> '; 26 | export const SUCCESS_SYMBOL = '✅ '; 27 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/filter-primitive.ts: -------------------------------------------------------------------------------- 1 | export type FilterPrimitive = { 2 | [key in keyof T]: Extract< 3 | T[key], 4 | boolean[] | number[] | string[] | boolean | number | string 5 | >; 6 | }; 7 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/get-declaration-creator.ts: -------------------------------------------------------------------------------- 1 | import type {OptionalKind, StatementStructures, StructureKind} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {coerceArray} from './coerce-array'; 5 | import type {Pattern} from './pattern'; 6 | import type {StructureType} from './structure-type'; 7 | import type {StructuredStatement} from './structured-statement'; 8 | 9 | export function getDeclarationCreator< 10 | Declaration extends StructuredStatement, 11 | Structure extends OptionalKind> = OptionalKind< 12 | StructureType 13 | >, 14 | CommonStructure extends Partial & { 15 | kind: StructureKind; 16 | } = Partial & { 17 | kind: StructureKind; 18 | }, 19 | >(common: CommonStructure, {position = null}: {position?: number | null} = {}) { 20 | return function addDeclarations( 21 | pattern: Pattern, 22 | structures: Structure | Structure[], 23 | ) { 24 | const files = getSourceFiles(pattern); 25 | 26 | files.forEach((file) => { 27 | const structuresWithKind = coerceArray(structures).map((structure) => ({ 28 | ...common, 29 | ...structure, 30 | })) as StatementStructures[]; 31 | 32 | if (position === null && typeof position !== 'number') { 33 | file.addStatements(structuresWithKind); 34 | } else { 35 | file.insertStatements(position, structuresWithKind); 36 | } 37 | }); 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/get-declaration-editor.ts: -------------------------------------------------------------------------------- 1 | import type {OptionalKind} from 'ts-morph'; 2 | import {Node, Structure} from 'ts-morph'; 3 | 4 | import {coerceArray} from './coerce-array'; 5 | import type {StructureEditor} from './structure-editor'; 6 | import type {StructureType} from './structure-type'; 7 | import type {StructuredStatement} from './structured-statement'; 8 | 9 | export function getDeclarationEditor< 10 | Declaration extends StructuredStatement, 11 | Structures extends StructureType = StructureType, 12 | >() { 13 | return function editDeclarations( 14 | declarations: Declaration | Declaration[], 15 | editor: StructureEditor>, 16 | ) { 17 | coerceArray(declarations).forEach((declaration) => { 18 | const newStructure: Structures = Object.assign( 19 | declaration.getStructure(), 20 | // TODO: refactor it to support new typings 21 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 22 | // @ts-ignore 23 | editor(declaration.getStructure(), declaration), 24 | ) as Structures; 25 | 26 | // todo: see https://github.com/dsherret/ts-morph/issues/882 27 | // if the issue is resolved code will be remove 28 | if (Structure.hasName(newStructure) && Node.isRenameable(declaration)) { 29 | declaration.rename(newStructure.name); 30 | delete (newStructure as {name?: string}).name; 31 | } 32 | 33 | declaration.set(newStructure); 34 | }); 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/get-declaration-getter.ts: -------------------------------------------------------------------------------- 1 | import type {Query} from './match-query'; 2 | import {matchQuery} from './match-query'; 3 | import type {Pattern} from './pattern'; 4 | import type {StructureType} from './structure-type'; 5 | import type {StructuredStatement} from './structured-statement'; 6 | 7 | export function getDeclarationGetter< 8 | Declaration extends StructuredStatement, 9 | Structure extends StructureType = StructureType, 10 | >(getFn: (pattern: Pattern) => Declaration[]) { 11 | return function getDeclaration( 12 | pattern: Pattern, 13 | query?: Query, 14 | ): Declaration[] { 15 | return getFn(pattern).filter((declaration) => { 16 | try { 17 | return matchQuery(declaration.getStructure(), query); 18 | } catch (error: unknown) { 19 | const path = declaration.getSourceFile().getFilePath(); 20 | const err = error as Error; 21 | 22 | throw new Error( 23 | `An error occurred in ${path}\n${err.message}\n${err.stack}`, 24 | ); 25 | } 26 | }); 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/get-declaration-remover.ts: -------------------------------------------------------------------------------- 1 | import {coerceArray} from './coerce-array'; 2 | 3 | export function getDeclarationRemover(): ( 4 | declarations: T | T[], 5 | ) => void { 6 | // tslint:disable-next-line:no-shadowed-variable 7 | return function removeDeclarations(declarations: T | T[]) { 8 | coerceArray(declarations).forEach((declaration) => { 9 | declaration.remove(); 10 | }); 11 | }; 12 | } 13 | 14 | export const removeDeclarations = getDeclarationRemover(); 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './array-flat'; 2 | export * from './coerce-array'; 3 | export * from './colored-log'; 4 | export * from './filter-primitive'; 5 | export * from './get-declaration-creator'; 6 | export * from './get-declaration-editor'; 7 | export * from './get-declaration-getter'; 8 | export * from './get-declaration-remover'; 9 | export * from './match-query'; 10 | export * from './pattern'; 11 | export * from './structure-editor'; 12 | export * from './structure-type'; 13 | export * from './structured-statement'; 14 | export * from './throw-file-not-found'; 15 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/pattern.ts: -------------------------------------------------------------------------------- 1 | export type Pattern = string[] | string; 2 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/structure-editor.ts: -------------------------------------------------------------------------------- 1 | import type {OptionalKind} from 'ts-morph'; 2 | 3 | import type {FilterPrimitive} from './filter-primitive'; 4 | import type {StructureType} from './structure-type'; 5 | import type {StructuredStatement} from './structured-statement'; 6 | 7 | export type StructureEditor< 8 | Declaration extends StructuredStatement, 9 | Structure extends OptionalKind> = OptionalKind< 10 | StructureType 11 | >, 12 | UpdatableData extends FilterPrimitive = FilterPrimitive, 13 | > = (structure: Structure, declaration: Declaration) => Partial; 14 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/structure-type.ts: -------------------------------------------------------------------------------- 1 | import type {Node, StructureKind, WriterFunction} from 'ts-morph'; 2 | 3 | export type StructureType = T extends Node & { 4 | set(structure: Record): unknown; 5 | getStructure(): infer S; 6 | } 7 | ? S & { 8 | name?: string; 9 | kind?: StructureKind; 10 | leadingTrivia?: Array | WriterFunction | string; 11 | trailingTrivia?: Array | WriterFunction | string; 12 | } 13 | : never; 14 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/structured-statement.ts: -------------------------------------------------------------------------------- 1 | import type {Node} from 'ts-morph'; 2 | 3 | import type {StructureType} from './structure-type'; 4 | 5 | export type StructuredStatement = Node & { 6 | set(structure: Partial>): unknown; 7 | getStructure(): StructureType; 8 | }; 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/utils/throw-file-not-found.ts: -------------------------------------------------------------------------------- 1 | export function throwFileNotFound(filePath: string): never { 2 | throw new Error(`File not found: ${filePath}`); 3 | } 4 | -------------------------------------------------------------------------------- /libs/ng-morph/src/variables/add-variables.ts: -------------------------------------------------------------------------------- 1 | import type {VariableStatement} from 'ts-morph'; 2 | import {StructureKind} from 'ts-morph'; 3 | 4 | import {getDeclarationCreator} from '../utils'; 5 | 6 | export const addVariables = getDeclarationCreator({ 7 | kind: StructureKind.VariableStatement, 8 | }); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/variables/edit-variables.ts: -------------------------------------------------------------------------------- 1 | import type {VariableStatement} from 'ts-morph'; 2 | 3 | import {getDeclarationEditor} from '../utils'; 4 | 5 | export const editVariables = getDeclarationEditor(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/src/variables/get-variables.ts: -------------------------------------------------------------------------------- 1 | import type {VariableStatement} from 'ts-morph'; 2 | 3 | import {getSourceFiles} from '../source-file'; 4 | import {arrayFlat, getDeclarationGetter} from '../utils'; 5 | 6 | export const getVariables = getDeclarationGetter((pattern) => 7 | arrayFlat(getSourceFiles(pattern).map((file) => file.getVariableStatements())), 8 | ); 9 | -------------------------------------------------------------------------------- /libs/ng-morph/src/variables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-variables'; 2 | export * from './edit-variables'; 3 | export * from './get-variables'; 4 | export * from './remove-variables'; 5 | -------------------------------------------------------------------------------- /libs/ng-morph/src/variables/remove-variables.ts: -------------------------------------------------------------------------------- 1 | import type {VariableStatement} from 'ts-morph'; 2 | 3 | import {getDeclarationRemover} from '../utils'; 4 | 5 | export const removeVariables = getDeclarationRemover(); 6 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-accessors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addAccessors, 6 | createProject, 7 | createSourceFile, 8 | getClasses, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | import {StructureKind} from 'ts-morph'; 14 | 15 | describe('addAccessors', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class A {} 27 | `, 28 | ); 29 | }); 30 | 31 | it('should add accessors', () => { 32 | addAccessors(getClasses('some/path/file.ts'), [ 33 | { 34 | name: 'setter', 35 | kind: StructureKind.SetAccessor, 36 | }, 37 | ]); 38 | 39 | saveActiveProject(); 40 | 41 | expect(host.readContent('some/path/file.ts')).toBe(` 42 | class A { 43 | set setter() { 44 | } 45 | } 46 | `); 47 | }); 48 | 49 | afterEach(() => { 50 | resetActiveProject(); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-classes.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addClasses, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addClasses', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile('some/path/file.ts', ''); 22 | }); 23 | 24 | it('should add classes', () => { 25 | addClasses('some/path/file.ts', { 26 | name: 'A', 27 | isDefaultExport: true, 28 | methods: [ 29 | { 30 | name: 'method', 31 | isStatic: true, 32 | statements: 'return 0', 33 | returnType: 'number', 34 | }, 35 | ], 36 | }); 37 | 38 | saveActiveProject(); 39 | 40 | expect(host.readContent('some/path/file.ts')).toBe(`export default class A { 41 | static method(): number { 42 | return 0 43 | } 44 | } 45 | `); 46 | }); 47 | 48 | afterEach(() => { 49 | resetActiveProject(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-constructors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addConstructors, 6 | createProject, 7 | createSourceFile, 8 | getClasses, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | import {Scope} from 'ts-morph'; 14 | 15 | describe('addConstructors', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class B { 27 | 28 | } 29 | `, 30 | ); 31 | }); 32 | 33 | it('should add constructors', () => { 34 | addConstructors(getClasses('some/path/file.ts', {name: 'B'}), { 35 | parameters: [ 36 | { 37 | decorators: [{name: 'Inject', arguments: ['SomeType']}], 38 | name: 'param', 39 | type: 'SomeType', 40 | }, 41 | ], 42 | scope: Scope.Protected, 43 | }); 44 | 45 | saveActiveProject(); 46 | 47 | expect(host.readContent('some/path/file.ts')).toBe(` 48 | class B { 49 | protected constructor(@Inject(SomeType) param: SomeType) { 50 | } 51 | } 52 | `); 53 | }); 54 | 55 | afterEach(() => { 56 | resetActiveProject(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-enums.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addEnums, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addEnums', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | console.log('Some log'); 25 | `, 26 | ); 27 | }); 28 | 29 | it('should add enums', () => { 30 | addEnums('some/path/file.ts', [ 31 | { 32 | name: 'Enum', 33 | isConst: true, 34 | members: [{name: 'First'}, {name: 'second'}], 35 | }, 36 | { 37 | name: 'EmptyEnum', 38 | isExported: true, 39 | }, 40 | ]); 41 | 42 | saveActiveProject(); 43 | 44 | expect(host.readContent('some/path/file.ts')).toBe(` 45 | console.log('Some log'); 46 | const enum Enum { 47 | First, 48 | second 49 | } 50 | 51 | export enum EmptyEnum { 52 | } 53 | `); 54 | }); 55 | 56 | afterEach(() => { 57 | resetActiveProject(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-exports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addExports, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addExports', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | console.log(a); 25 | `, 26 | ); 27 | }); 28 | 29 | it('should add exports', () => { 30 | addExports('some/path/file.ts', [ 31 | { 32 | namedExports: ['a'], 33 | moduleSpecifier: 'b', 34 | }, 35 | { 36 | namespaceExport: 'c', 37 | moduleSpecifier: 'd', 38 | }, 39 | { 40 | namedExports: ['e'], 41 | moduleSpecifier: 'f', 42 | isTypeOnly: true, 43 | }, 44 | ]); 45 | 46 | saveActiveProject(); 47 | 48 | expect(host.readContent('some/path/file.ts')).toBe(` 49 | console.log(a); 50 | export { a } from "b"; 51 | export * as c from "d"; 52 | export type { e } from "f"; 53 | `); 54 | }); 55 | 56 | afterEach(() => { 57 | resetActiveProject(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-functions.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addFunctions, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addFunctions', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | function a(){ 25 | return 'a' 26 | } 27 | `, 28 | ); 29 | }); 30 | 31 | it('should add a function', () => { 32 | addFunctions('some/**/**.ts', { 33 | isExported: true, 34 | name: 'b', 35 | statements: "return 'b'", 36 | }); 37 | 38 | saveActiveProject(); 39 | 40 | expect(host.readContent('some/path/file.ts')).toBe(` 41 | function a(){ 42 | return 'a' 43 | } 44 | export function b() { 45 | return 'b' 46 | } 47 | `); 48 | }); 49 | 50 | afterEach(() => { 51 | resetActiveProject(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-imports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addImports, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addImports', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | console.log(a); 25 | `, 26 | ); 27 | }); 28 | 29 | it('should add imports', () => { 30 | addImports('some/path/file.ts', [ 31 | { 32 | namedImports: ['a'], 33 | moduleSpecifier: 'b', 34 | }, 35 | { 36 | namespaceImport: 'c', 37 | moduleSpecifier: 'd', 38 | }, 39 | { 40 | defaultImport: 'c', 41 | moduleSpecifier: 'd', 42 | }, 43 | { 44 | namedImports: ['e'], 45 | moduleSpecifier: 'f', 46 | isTypeOnly: true, 47 | }, 48 | ]); 49 | 50 | saveActiveProject(); 51 | 52 | expect(host.readContent('some/path/file.ts')).toBe(`import { a } from "b"; 53 | import * as c from "d"; 54 | import c from "d"; 55 | import type { e } from "f"; 56 | 57 | console.log(a); 58 | `); 59 | }); 60 | 61 | afterEach(() => { 62 | resetActiveProject(); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-interfaces.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addInterfaces, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addInterfaces', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile('some/path/file.ts', ''); 22 | }); 23 | 24 | it('should add Interfaces', () => { 25 | addInterfaces('some/path/file.ts', { 26 | name: 'A', 27 | properties: [{name: 's', type: 'string'}], 28 | methods: [{name: 'method', returnType: 'number'}], 29 | }); 30 | 31 | saveActiveProject(); 32 | 33 | expect(host.readContent('some/path/file.ts')).toBe(`interface A { 34 | s: string; 35 | method(): number; 36 | } 37 | `); 38 | }); 39 | 40 | afterEach(() => { 41 | resetActiveProject(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-methods.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addMethods, 6 | createProject, 7 | createSourceFile, 8 | getClasses, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('addMethods', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | class A {} 26 | class B {} 27 | `, 28 | ); 29 | }); 30 | 31 | it('should add methods', () => { 32 | addMethods(getClasses('some/path/file.ts', {name: 'B'}), { 33 | name: 'test', 34 | statements: 'return 0;', 35 | returnType: 'number', 36 | }); 37 | 38 | saveActiveProject(); 39 | 40 | expect(host.readContent('some/path/file.ts')).toBe(` 41 | class A {} 42 | class B { 43 | test(): number { 44 | return 0; 45 | } 46 | } 47 | `); 48 | }); 49 | 50 | afterEach(() => { 51 | resetActiveProject(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-params.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addParams, 6 | createProject, 7 | createSourceFile, 8 | getClasses, 9 | getMethods, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('addParams', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class B { 27 | add(){} 28 | } 29 | `, 30 | ); 31 | }); 32 | 33 | it('should add params', () => { 34 | addParams(getMethods(getClasses('some/path/file.ts'), {name: 'add'}), [ 35 | { 36 | name: 'param', 37 | type: 'number', 38 | decorators: [{name: 'Pure', arguments: []}], 39 | }, 40 | ]); 41 | 42 | saveActiveProject(); 43 | 44 | expect(host.readContent('some/path/file.ts')).toBe(` 45 | class B { 46 | add(@Pure() param: number){} 47 | } 48 | `); 49 | }); 50 | 51 | afterEach(() => { 52 | resetActiveProject(); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-properties.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addProperties, 6 | createProject, 7 | createSourceFile, 8 | getClasses, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('addProperties', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | class A {} 26 | class B {} 27 | `, 28 | ); 29 | }); 30 | 31 | it('should add properties', () => { 32 | addProperties(getClasses('some/path/file.ts', {name: 'B'}), { 33 | name: 'test', 34 | initializer: '3', 35 | }); 36 | 37 | saveActiveProject(); 38 | 39 | expect(host.readContent('some/path/file.ts')).toBe(` 40 | class A {} 41 | class B { 42 | test = 3; 43 | } 44 | `); 45 | }); 46 | 47 | afterEach(() => { 48 | resetActiveProject(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-type-aliases.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | addTypeAliases, 6 | createProject, 7 | createSourceFile, 8 | resetActiveProject, 9 | saveActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('addTypeAliases', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile('some/path/file.ts', ''); 22 | }); 23 | 24 | it('should add type aliases', () => { 25 | addTypeAliases('some/path/file.ts', { 26 | name: 'A', 27 | typeParameters: ['T'], 28 | type: 'T[]', 29 | }); 30 | 31 | saveActiveProject(); 32 | 33 | expect(host.readContent('some/path/file.ts')).toBe(`type A = T[]; 34 | `); 35 | }); 36 | 37 | afterEach(() => { 38 | resetActiveProject(); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/add-variables.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | resetActiveProject, 8 | saveActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | import {VariableDeclarationKind} from 'ts-morph'; 12 | 13 | import {addVariables} from '../src/variables/add-variables'; 14 | 15 | describe('addVariables', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile('some/path/file.ts', ''); 24 | }); 25 | 26 | it('should add variables', () => { 27 | addVariables('some/path/file.ts', { 28 | declarationKind: VariableDeclarationKind.Const, 29 | declarations: [ 30 | { 31 | name: 'name', 32 | initializer: "'value'", 33 | }, 34 | ], 35 | }); 36 | 37 | saveActiveProject(); 38 | 39 | expect(host.readContent('some/path/file.ts')).toBe(`const name = 'value'; 40 | `); 41 | }); 42 | 43 | afterEach(() => { 44 | resetActiveProject(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-accessors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editAccessors, 8 | getAccessors, 9 | getClasses, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('editAccessors', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class A { 27 | set setter(value){ 28 | 29 | } 30 | } 31 | `, 32 | ); 33 | }); 34 | 35 | it('should edit accessors', () => { 36 | const declarations = getAccessors(getClasses('some/path/file.ts')); 37 | 38 | editAccessors(declarations, () => ({ 39 | name: 'anotherName', 40 | })); 41 | 42 | saveActiveProject(); 43 | 44 | expect(host.readContent('some/path/file.ts')).toBe(` 45 | class A { 46 | set anotherName(value){ 47 | 48 | } 49 | } 50 | `); 51 | }); 52 | 53 | afterEach(() => { 54 | resetActiveProject(); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-classes.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editClasses, 8 | getClasses, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('editClasses', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | class A {} 26 | 27 | const a: A; 28 | `, 29 | ); 30 | }); 31 | 32 | it('should edit classes', () => { 33 | const classes = getClasses('some/path/file.ts'); 34 | 35 | editClasses(classes, () => ({ 36 | isExported: true, 37 | name: 'B', 38 | })); 39 | 40 | saveActiveProject(); 41 | 42 | expect(host.readContent('some/path/file.ts')).toBe(` 43 | export class B {} 44 | 45 | const a: B; 46 | `); 47 | }); 48 | 49 | afterEach(() => { 50 | resetActiveProject(); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-constructors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editConstructors, 8 | getClasses, 9 | getConstructors, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | import {Scope} from 'ts-morph'; 15 | 16 | describe('editConstructors', () => { 17 | let host: UnitTestTree; 18 | 19 | beforeEach(() => { 20 | host = new UnitTestTree(new HostTree()); 21 | 22 | setActiveProject(createProject(host)); 23 | 24 | createSourceFile( 25 | 'some/path/file.ts', 26 | ` 27 | class A { 28 | constructor(){ 29 | 30 | } 31 | } 32 | `, 33 | ); 34 | }); 35 | 36 | it('should edit constructors', () => { 37 | const declarations = getConstructors(getClasses('some/path/file.ts')); 38 | 39 | editConstructors(declarations, () => ({ 40 | scope: Scope.Protected, 41 | })); 42 | 43 | saveActiveProject(); 44 | 45 | expect(host.readContent('some/path/file.ts')).toBe(` 46 | class A { 47 | protected constructor(){ 48 | 49 | } 50 | } 51 | `); 52 | }); 53 | 54 | afterEach(() => { 55 | resetActiveProject(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-decorators.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editDecorators, 8 | getClasses, 9 | getDecorators, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('editDecorators', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | @Component({ 27 | selector: 'a' 28 | }) 29 | class A{ 30 | 31 | } 32 | `, 33 | ); 34 | }); 35 | 36 | it('should edit decorators', () => { 37 | const declarations = getDecorators(getClasses('some/path/file.ts')); 38 | 39 | editDecorators(declarations, () => ({ 40 | name: 'Directive', 41 | })); 42 | 43 | saveActiveProject(); 44 | 45 | expect(host.readContent('some/path/file.ts')).toBe(` 46 | @Directive({ 47 | selector: 'a' 48 | }) 49 | class A{ 50 | 51 | } 52 | `); 53 | }); 54 | 55 | afterEach(() => { 56 | resetActiveProject(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-enums.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editEnums, 8 | getEnums, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('editEnums', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | enum Test {First} 26 | 27 | let a: Test; 28 | const b = Test.First; 29 | `, 30 | ); 31 | }); 32 | 33 | it('should edit enums', () => { 34 | const declarations = getEnums('some/path/file.ts'); 35 | 36 | editEnums(declarations, () => ({ 37 | name: 'Name', 38 | })); 39 | 40 | saveActiveProject(); 41 | 42 | expect(host.readContent('some/path/file.ts')).toBe(` 43 | enum Name { 44 | First 45 | } 46 | 47 | let a: Name; 48 | const b = Name.First; 49 | `); 50 | }); 51 | 52 | afterEach(() => { 53 | resetActiveProject(); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-exports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | resetActiveProject, 8 | saveActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | import {editExports} from '../src/exports/edit-exports'; 13 | import {getExports} from '../src/exports/get-exports'; 14 | 15 | describe('editExports', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | export { a } from 'b'; 27 | 28 | console.log(a); 29 | `, 30 | ); 31 | }); 32 | 33 | it('should edit exports', () => { 34 | const exports = getExports('some/path/file.ts'); 35 | 36 | editExports(exports, () => ({ 37 | namedExports: ['b,c'], 38 | })); 39 | 40 | saveActiveProject(); 41 | 42 | expect(host.readContent('some/path/file.ts')).toBe(` 43 | export { b,c } from 'b'; 44 | 45 | console.log(a); 46 | `); 47 | }); 48 | 49 | afterEach(() => { 50 | resetActiveProject(); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-functions.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editFunctions, 8 | getFunctions, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('editFunctions', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | function a(){ 26 | return 'a' 27 | } 28 | `, 29 | ); 30 | }); 31 | 32 | it('should rename a function', () => { 33 | const functions = getFunctions('some/**/**.ts'); 34 | 35 | editFunctions(functions, () => ({ 36 | isExported: true, 37 | name: 'b', 38 | statements: "return 'b'", 39 | })); 40 | 41 | saveActiveProject(); 42 | 43 | expect(host.readContent('some/path/file.ts')).toBe(` 44 | export function b(){ 45 | return 'b' 46 | } 47 | `); 48 | }); 49 | 50 | afterEach(() => { 51 | resetActiveProject(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-imports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editImports, 8 | getImports, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('editImports', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | import { a } from 'b'; 26 | 27 | console.log(a); 28 | `, 29 | ); 30 | }); 31 | 32 | it('should edit imports', () => { 33 | const imports = getImports('some/path/file.ts'); 34 | 35 | editImports(imports, () => ({ 36 | namedImports: ['b,c'], 37 | })); 38 | 39 | saveActiveProject(); 40 | 41 | expect(host.readContent('some/path/file.ts')).toBe(` 42 | import { b,c } from 'b'; 43 | 44 | console.log(a); 45 | `); 46 | }); 47 | 48 | afterEach(() => { 49 | resetActiveProject(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-interfaces.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editInterfaces, 8 | getInterfaces, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('editInterfaces', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | interface A {} 26 | 27 | const a: A; 28 | `, 29 | ); 30 | }); 31 | 32 | it('should edit Interfaces', () => { 33 | const declarations = getInterfaces('some/path/file.ts'); 34 | 35 | editInterfaces(declarations, () => ({ 36 | name: 'B', 37 | })); 38 | 39 | saveActiveProject(); 40 | 41 | expect(host.readContent('some/path/file.ts')).toBe(` 42 | interface B {} 43 | 44 | const a: B; 45 | `); 46 | }); 47 | 48 | afterEach(() => { 49 | resetActiveProject(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-methods.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editMethods, 8 | getClasses, 9 | getMethods, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('editMethods', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class A { 27 | test(){} 28 | } 29 | 30 | A.prototype.test(); 31 | `, 32 | ); 33 | }); 34 | 35 | it('should edit methods', () => { 36 | const declarations = getMethods(getClasses('some/path/file.ts')); 37 | 38 | editMethods(declarations, ({isAsync}) => ({ 39 | name: 'b', 40 | isAsync: !isAsync, 41 | })); 42 | 43 | saveActiveProject(); 44 | 45 | expect(host.readContent('some/path/file.ts')).toBe(` 46 | class A { 47 | async b(){} 48 | } 49 | 50 | A.prototype.b(); 51 | `); 52 | }); 53 | 54 | afterEach(() => { 55 | resetActiveProject(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-params.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editParams, 8 | getClasses, 9 | getConstructors, 10 | getParams, 11 | resetActiveProject, 12 | saveActiveProject, 13 | setActiveProject, 14 | } from 'ng-morph'; 15 | import {Scope} from 'ts-morph'; 16 | 17 | describe('editParams', () => { 18 | let host: UnitTestTree; 19 | 20 | beforeEach(() => { 21 | host = new UnitTestTree(new HostTree()); 22 | 23 | setActiveProject(createProject(host)); 24 | 25 | createSourceFile( 26 | 'some/path/file.ts', 27 | ` 28 | class B { 29 | constructor(param1: number, param2: string){} 30 | } 31 | `, 32 | ); 33 | }); 34 | 35 | it('should edit params', () => { 36 | const declarations = getParams(getConstructors(getClasses('some/path/file.ts')), { 37 | name: 'param2', 38 | }); 39 | 40 | editParams(declarations, () => ({ 41 | scope: Scope.Private, 42 | name: 'anotherParam', 43 | type: 'number', 44 | initializer: 'Math.PI', 45 | })); 46 | 47 | saveActiveProject(); 48 | 49 | expect(host.readContent('some/path/file.ts')).toBe(` 50 | class B { 51 | constructor(param1: number, private anotherParam: number = Math.PI){} 52 | } 53 | `); 54 | }); 55 | 56 | afterEach(() => { 57 | resetActiveProject(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-properties.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editProperties, 8 | getClasses, 9 | getProperties, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('editProperties', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class A { 27 | b = 0; 28 | } 29 | `, 30 | ); 31 | }); 32 | 33 | it('should edit properties', () => { 34 | const declarations = getProperties(getClasses('some/path/file.ts')); 35 | 36 | editProperties(declarations, () => ({ 37 | name: 'b', 38 | initializer: "'s'", 39 | })); 40 | 41 | saveActiveProject(); 42 | 43 | expect(host.readContent('some/path/file.ts')).toBe(` 44 | class A { 45 | b = 's'; 46 | } 47 | `); 48 | }); 49 | 50 | afterEach(() => { 51 | resetActiveProject(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-type-aliases.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editTypeAliases, 8 | getTypeAliases, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('editTypeAliases', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile('some/path/file.ts', 'type A = string[]; let a: A;'); 23 | }); 24 | 25 | it('should edit type aliases', () => { 26 | const declarations = getTypeAliases('some/path/file.ts'); 27 | 28 | editTypeAliases(declarations, () => ({ 29 | name: 'B', 30 | })); 31 | 32 | saveActiveProject(); 33 | 34 | expect(host.readContent('some/path/file.ts')).toBe( 35 | 'type B = string[]; let a: B;', 36 | ); 37 | }); 38 | 39 | afterEach(() => { 40 | resetActiveProject(); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/edit-variables.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | editVariables, 8 | getVariables, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | import {VariableDeclarationKind} from 'ts-morph'; 14 | 15 | describe('editVariables', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile('some/path/file.ts', "const a = 's'"); 24 | }); 25 | 26 | it('should edit variables', () => { 27 | const declarations = getVariables('some/path/file.ts'); 28 | 29 | editVariables(declarations, () => ({ 30 | declarationKind: VariableDeclarationKind.Let, 31 | })); 32 | 33 | saveActiveProject(); 34 | 35 | expect(host.readContent('some/path/file.ts')).toBe("let a = 's'"); 36 | }); 37 | 38 | afterEach(() => { 39 | resetActiveProject(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-accessors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getAccessors, 8 | getClasses, 9 | resetActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('getAccessors', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | class A { 25 | get getter(){} 26 | } 27 | `, 28 | ); 29 | 30 | createSourceFile( 31 | 'some/path/one-more-file.ts', 32 | ` 33 | class B { 34 | set setter(value){} 35 | } 36 | `, 37 | ); 38 | }); 39 | 40 | it('should find two accessors', () => { 41 | const declarations = getAccessors(getClasses('some/path/**.ts')); 42 | 43 | expect(declarations.length).toBe(2); 44 | }); 45 | 46 | it('should find one accessor', () => { 47 | const declarations = getAccessors(getClasses('some/path/file.ts')); 48 | 49 | expect(declarations.length).toBe(1); 50 | }); 51 | 52 | it('should find one accessor by name', () => { 53 | const declarations = getAccessors(getClasses('some/path/**.ts'), { 54 | name: 'setter', 55 | }); 56 | 57 | expect(declarations.length).toBe(1); 58 | }); 59 | 60 | afterEach(() => { 61 | resetActiveProject(); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-bootstrap-application-fn.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getBootstrapApplicationFn, 8 | setActiveProject, 9 | } from 'ng-morph'; 10 | import {Node} from 'ts-morph'; 11 | 12 | describe('getBootstrapApplicationFn', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | }); 20 | 21 | it('should find the bootstrap function', () => { 22 | createSourceFile( 23 | 'src/main.ts', 24 | `import {bootstrapApplication} from '@angular/platform-browser'; 25 | import {AppComponent} from './app/app.component'; 26 | import {environment} from './environments/environment'; 27 | 28 | if (environment.production) { 29 | enableProdMode(); 30 | } 31 | 32 | bootstrapApplication(AppComponent) 33 | `, 34 | ); 35 | const bootstrapFn = getBootstrapApplicationFn('src/main.ts'); 36 | 37 | expect(bootstrapFn?.getText()).toBe('bootstrapApplication(AppComponent)'); 38 | expect(Node.isCallExpression(bootstrapFn)).toBe(true); 39 | }); 40 | 41 | it('should return undefined if bootstrap function is not found', () => { 42 | createSourceFile('src/main.ts', ''); 43 | const bootstrapFn = getBootstrapApplicationFn('src/main.ts'); 44 | 45 | expect(bootstrapFn).toBeUndefined(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-bootstrap-fn.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getBootstrapFn, 8 | setActiveProject, 9 | } from 'ng-morph'; 10 | import {Node} from 'ts-morph'; 11 | 12 | describe('getBootstrapFn', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | }); 20 | 21 | it('should find the bootstrap function', () => { 22 | createSourceFile( 23 | 'src/main.ts', 24 | `import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 25 | import {AppModule} from './app/app.module'; 26 | import {environment} from './environments/environment'; 27 | 28 | if (environment.production) { 29 | enableProdMode(); 30 | } 31 | 32 | platformBrowserDynamic() 33 | .bootstrapModule(AppModule) 34 | .catch(err => console.log(err)); 35 | `, 36 | ); 37 | const bootstrapFn = getBootstrapFn('src/main.ts'); 38 | 39 | expect(bootstrapFn?.getText()).toBe(`platformBrowserDynamic() 40 | .bootstrapModule(AppModule)`); 41 | expect(Node.isCallExpression(bootstrapFn)).toBe(true); 42 | }); 43 | 44 | it('should return undefined if bootstrap function is not found', () => { 45 | createSourceFile('src/main.ts', ''); 46 | const bootstrapFn = getBootstrapFn('src/main.ts'); 47 | 48 | expect(bootstrapFn).toBeUndefined(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-classes.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | describe('getClasses', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | 20 | createSourceFile( 21 | 'some/path/file.ts', 22 | ` 23 | class A { } 24 | `, 25 | ); 26 | 27 | createSourceFile( 28 | 'some/path/one-more-file.ts', 29 | ` 30 | class B { } 31 | `, 32 | ); 33 | }); 34 | 35 | it('should find two classes', () => { 36 | const exports = getClasses('some/path/**.ts'); 37 | 38 | expect(exports.length).toBe(2); 39 | }); 40 | 41 | it('should find one class', () => { 42 | const exports = getClasses('some/path/file.ts'); 43 | 44 | expect(exports.length).toBe(1); 45 | }); 46 | 47 | it('should find one export by class name', () => { 48 | const exports = getClasses('some/path/**.ts', { 49 | name: 'B', 50 | }); 51 | 52 | expect(exports.length).toBe(1); 53 | }); 54 | 55 | afterEach(() => { 56 | resetActiveProject(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-constructors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getConstructors, 9 | resetActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | import {Scope} from 'ts-morph'; 13 | 14 | describe('getConstructors', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | class A { 26 | constructor(a: string | number){ 27 | 28 | } 29 | } 30 | `, 31 | ); 32 | 33 | createSourceFile( 34 | 'some/path/one-more-file.ts', 35 | ` 36 | class B { 37 | protected constructor(a: string | number){ 38 | 39 | } 40 | } 41 | `, 42 | ); 43 | }); 44 | 45 | it('should find two constructors', () => { 46 | const declarations = getConstructors(getClasses('some/path/**.ts')); 47 | 48 | expect(declarations.length).toBe(2); 49 | }); 50 | 51 | it('should find one constructor', () => { 52 | const declarations = getConstructors(getClasses('some/path/file.ts')); 53 | 54 | expect(declarations.length).toBe(1); 55 | }); 56 | 57 | it('should find one constructor by name', () => { 58 | const declarations = getConstructors(getClasses('some/path/**.ts'), { 59 | scope: Scope.Protected, 60 | }); 61 | 62 | expect(declarations.length).toBe(1); 63 | }); 64 | 65 | afterEach(() => { 66 | resetActiveProject(); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-enums.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getEnums, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | describe('getEnums', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | 20 | createSourceFile( 21 | 'some/path/file.ts', 22 | ` 23 | enum A { } 24 | `, 25 | ); 26 | 27 | createSourceFile( 28 | 'some/path/one-more-file.ts', 29 | ` 30 | enum B { 31 | Wow 32 | } 33 | `, 34 | ); 35 | }); 36 | 37 | it('should find two enums', () => { 38 | const declarations = getEnums('some/path/**.ts'); 39 | 40 | expect(declarations.length).toBe(2); 41 | }); 42 | 43 | it('should find one enum', () => { 44 | const declarations = getEnums('some/path/file.ts'); 45 | 46 | expect(declarations.length).toBe(1); 47 | }); 48 | 49 | it('should find one enum by name', () => { 50 | const declarations = getEnums('some/path/**.ts', { 51 | name: 'B', 52 | }); 53 | 54 | expect(declarations.length).toBe(1); 55 | }); 56 | 57 | afterEach(() => { 58 | resetActiveProject(); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-exports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getExports, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | describe('getExports', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | 20 | createSourceFile( 21 | 'some/path/file.ts', 22 | ` 23 | export { a } from 'b'; 24 | `, 25 | ); 26 | 27 | createSourceFile( 28 | 'some/path/one-more-file.ts', 29 | ` 30 | export { c } from 'd'; 31 | `, 32 | ); 33 | }); 34 | 35 | it('should find two exports', () => { 36 | const exports = getExports('some/path/**.ts'); 37 | 38 | expect(exports.length).toBe(2); 39 | }); 40 | 41 | it('should find one export', () => { 42 | const exports = getExports('some/path/file.ts'); 43 | 44 | expect(exports.length).toBe(1); 45 | }); 46 | 47 | it('should find one export by name', () => { 48 | const exports = getExports('some/path/**.ts', { 49 | moduleSpecifier: 'd', 50 | }); 51 | 52 | expect(exports.length).toBe(1); 53 | }); 54 | 55 | afterEach(() => { 56 | resetActiveProject(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-functions.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getFunctions, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | import {Node} from 'ts-morph'; 12 | 13 | describe('getFunctions', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | function a(){ 25 | return 'a' 26 | } 27 | `, 28 | ); 29 | }); 30 | 31 | it('should find all functions', () => { 32 | const functions = getFunctions('some/**/**.ts'); 33 | 34 | expect(functions.map(Node.isFunctionDeclaration)).toEqual([true]); 35 | }); 36 | 37 | afterEach(() => { 38 | resetActiveProject(); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-interfaces.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getInterfaces, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | describe('getInterfaces', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | 20 | createSourceFile( 21 | 'some/path/file.ts', 22 | ` 23 | interface A {} 24 | `, 25 | ); 26 | 27 | createSourceFile( 28 | 'some/path/one-more-file.ts', 29 | ` 30 | interface B {} 31 | `, 32 | ); 33 | }); 34 | 35 | it('should find two Interfaces', () => { 36 | const declarations = getInterfaces('some/path/**.ts'); 37 | 38 | expect(declarations.length).toBe(2); 39 | }); 40 | 41 | it('should find one interface', () => { 42 | const declarations = getInterfaces('some/path/file.ts'); 43 | 44 | expect(declarations.length).toBe(1); 45 | }); 46 | 47 | it('should find one interface by name', () => { 48 | const declarations = getInterfaces('some/path/**.ts', { 49 | name: 'B', 50 | }); 51 | 52 | expect(declarations.length).toBe(1); 53 | }); 54 | 55 | afterEach(() => { 56 | resetActiveProject(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-main-module.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {beforeEach, describe, expect, it} from '@jest/globals'; 4 | import {createProject, createSourceFile, getMainModule, setActiveProject} from 'ng-morph'; 5 | import {Node} from 'ts-morph'; 6 | 7 | describe('getMainModule', () => { 8 | let host: UnitTestTree; 9 | 10 | beforeEach(() => { 11 | host = new UnitTestTree(new HostTree()); 12 | 13 | setActiveProject(createProject(host)); 14 | 15 | createSourceFile( 16 | 'src/main.ts', 17 | `import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 18 | import {AppModule} from './app/app.module'; 19 | import {environment} from './environments/environment'; 20 | 21 | if (environment.production) { 22 | enableProdMode(); 23 | } 24 | 25 | platformBrowserDynamic() 26 | .bootstrapModule(AppModule) 27 | .catch(err => console.log(err)); 28 | `, 29 | ); 30 | 31 | createSourceFile( 32 | 'src/app/app.module.ts', 33 | ` 34 | import {NgModule} from '@angular/core'; 35 | 36 | @NgModule() 37 | export class AppModule { 38 | 39 | } 40 | `, 41 | ); 42 | }); 43 | 44 | it('should find the AppModule class', () => { 45 | const classDeclaration = getMainModule('src/main.ts'); 46 | 47 | expect(classDeclaration?.getText()).toBe(`@NgModule() 48 | export class AppModule { 49 | 50 | }`); 51 | expect(Node.isClassDeclaration(classDeclaration)).toBe(true); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-methods.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getMethods, 9 | resetActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('getMethods', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | class A { 25 | b(){} 26 | } 27 | `, 28 | ); 29 | 30 | createSourceFile( 31 | 'some/path/one-more-file.ts', 32 | ` 33 | class B { 34 | static d(){} 35 | } 36 | `, 37 | ); 38 | }); 39 | 40 | it('should find two methods', () => { 41 | const declarations = getMethods(getClasses('some/path/**.ts')); 42 | 43 | expect(declarations.length).toBe(2); 44 | }); 45 | 46 | it('should find one method', () => { 47 | const declarations = getMethods(getClasses('some/path/file.ts')); 48 | 49 | expect(declarations.length).toBe(1); 50 | }); 51 | 52 | it('should find one method by name', () => { 53 | const declarations = getMethods(getClasses('some/path/**.ts'), { 54 | name: 'd', 55 | isStatic: true, 56 | }); 57 | 58 | expect(declarations.length).toBe(1); 59 | }); 60 | 61 | afterEach(() => { 62 | resetActiveProject(); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-params.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getConstructors, 9 | getParams, 10 | resetActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('getParams', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | class A { 26 | constructor(value){} 27 | } 28 | `, 29 | ); 30 | 31 | createSourceFile( 32 | 'some/path/one-more-file.ts', 33 | ` 34 | class B { 35 | constructor(@Inject(SOME_TOKEN) name: number = Math.PI){} 36 | } 37 | `, 38 | ); 39 | }); 40 | 41 | it('should find two params', () => { 42 | const declarations = getParams(getConstructors(getClasses('some/path/**.ts'))); 43 | 44 | expect(declarations.length).toBe(2); 45 | }); 46 | 47 | it('should find one param', () => { 48 | const declarations = getParams(getConstructors(getClasses('some/path/file.ts'))); 49 | 50 | expect(declarations.length).toBe(1); 51 | }); 52 | 53 | it('should find one param by name', () => { 54 | const declarations = getParams(getConstructors(getClasses('some/path/**.ts')), { 55 | initializer: 'Math.PI', 56 | }); 57 | 58 | expect(declarations.length).toBe(1); 59 | }); 60 | 61 | afterEach(() => { 62 | resetActiveProject(); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-project-targets.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google Inc. All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | import {EmptyTree} from '@angular-devkit/schematics'; 9 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 10 | import {beforeEach, describe, expect, it} from '@jest/globals'; 11 | import {getProjectTarget, getProjectTargets} from 'ng-morph'; 12 | 13 | describe('get project targets', () => { 14 | describe('getProjectTargets', () => { 15 | let tree: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | tree = new UnitTestTree(new EmptyTree()); 19 | tree.create( 20 | 'angular.json', 21 | JSON.stringify({ 22 | version: 1, 23 | projects: { 24 | migrations: {}, 25 | core: { 26 | root: '', 27 | }, 28 | }, 29 | }), 30 | ); 31 | }); 32 | 33 | it('should return all projects', () => { 34 | const projects = getProjectTargets(tree); 35 | 36 | expect([...projects]).toEqual([ 37 | ['migrations', {}], 38 | ['core', {root: ''}], 39 | ]); 40 | }); 41 | 42 | it('should return the core project', () => { 43 | const project = getProjectTarget(tree, 'core'); 44 | 45 | expect(project).toEqual({root: ''}); 46 | }); 47 | 48 | it('should return null', () => { 49 | const project = getProjectTarget(tree, 'some-project'); 50 | 51 | expect(project).toBeNull(); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-properties.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getProperties, 9 | resetActiveProject, 10 | setActiveProject, 11 | } from 'ng-morph'; 12 | 13 | describe('getProperties', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile( 22 | 'some/path/file.ts', 23 | ` 24 | class A { 25 | b = 1; 26 | } 27 | `, 28 | ); 29 | 30 | createSourceFile( 31 | 'some/path/one-more-file.ts', 32 | ` 33 | class B { 34 | static d = 's'; 35 | 36 | static hello2 = 'hello'; 37 | } 38 | `, 39 | ); 40 | }); 41 | 42 | it('should find two properties', () => { 43 | const declarations = getProperties(getClasses('some/path/**.ts')); 44 | 45 | expect(declarations.length).toBe(3); 46 | }); 47 | 48 | it('should find one property', () => { 49 | const declarations = getProperties(getClasses('some/path/file.ts')); 50 | 51 | expect(declarations.length).toBe(1); 52 | }); 53 | 54 | it('should find one property by name pattern **', () => { 55 | const declarations = getProperties(getClasses('some/path/**.ts'), { 56 | name: 'd', 57 | isStatic: true, 58 | }); 59 | 60 | expect(declarations.length).toBe(1); 61 | }); 62 | 63 | it('should find one property by blob pattern **/*', () => { 64 | const declarations = getProperties(getClasses('**/*.ts'), { 65 | name: 'hello*', 66 | isStatic: true, 67 | }); 68 | 69 | expect(declarations.length).toBe(1); 70 | }); 71 | 72 | afterEach(() => { 73 | resetActiveProject(); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-source-files.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getSourceFiles, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | describe('getSourceFiles', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | 20 | createSourceFile('test.ts', ''); 21 | createSourceFile('some/test.ts', ''); 22 | createSourceFile('some/path/test.ts', ''); 23 | }); 24 | 25 | it('should find all source files', () => { 26 | const sourceFiles = getSourceFiles('some/**/*.ts'); 27 | 28 | expect(sourceFiles.length).toBe(2); 29 | }); 30 | 31 | it('should find three source files', () => { 32 | const sourceFiles = getSourceFiles('**/*.ts'); 33 | 34 | expect(sourceFiles.length).toBe(3); 35 | }); 36 | 37 | it('should find one source file', () => { 38 | const sourceFiles = getSourceFiles('some/test.ts'); 39 | 40 | expect(sourceFiles.length).toBe(1); 41 | }); 42 | 43 | afterEach(() => { 44 | resetActiveProject(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-type-aliases.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getTypeAliases, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | 12 | describe('getTypeAliases', () => { 13 | let host: UnitTestTree; 14 | 15 | beforeEach(() => { 16 | host = new UnitTestTree(new HostTree()); 17 | 18 | setActiveProject(createProject(host)); 19 | 20 | createSourceFile('some/path/file.ts', 'type A = string[];'); 21 | 22 | createSourceFile('some/path/one-more-file.ts', 'type B = number | string;'); 23 | }); 24 | 25 | it('should find two type aliases', () => { 26 | const declarations = getTypeAliases('some/path/**.ts'); 27 | 28 | expect(declarations.length).toBe(2); 29 | }); 30 | 31 | it('should find one type aliases', () => { 32 | const declarations = getTypeAliases('some/path/file.ts'); 33 | 34 | expect(declarations.length).toBe(1); 35 | }); 36 | 37 | it('should find one type alias by name', () => { 38 | const declarations = getTypeAliases('some/path/**.ts', { 39 | name: 'B', 40 | }); 41 | 42 | expect(declarations.length).toBe(1); 43 | }); 44 | 45 | afterEach(() => { 46 | resetActiveProject(); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/get-variables.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getVariables, 8 | resetActiveProject, 9 | setActiveProject, 10 | } from 'ng-morph'; 11 | import {VariableDeclarationKind} from 'ts-morph'; 12 | 13 | describe('getVariables', () => { 14 | let host: UnitTestTree; 15 | 16 | beforeEach(() => { 17 | host = new UnitTestTree(new HostTree()); 18 | 19 | setActiveProject(createProject(host)); 20 | 21 | createSourceFile('some/path/file.ts', 'const a;'); 22 | 23 | createSourceFile('some/path/one-more-file.ts', 'var b = {};'); 24 | }); 25 | 26 | it('should find two variables', () => { 27 | const declarations = getVariables('some/path/**.ts'); 28 | 29 | expect(declarations.length).toBe(2); 30 | }); 31 | 32 | it('should find one variable', () => { 33 | const declarations = getVariables('some/path/file.ts'); 34 | 35 | expect(declarations.length).toBe(1); 36 | }); 37 | 38 | it('should find one variable by variable kind', () => { 39 | const declarations = getVariables('some/path/**.ts', { 40 | declarationKind: VariableDeclarationKind.Var, 41 | }); 42 | 43 | expect(declarations.length).toBe(1); 44 | }); 45 | 46 | afterEach(() => { 47 | resetActiveProject(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/json-file-content.spec.ts: -------------------------------------------------------------------------------- 1 | import {describe, expect, it} from '@jest/globals'; 2 | import {JSONFileContent} from 'ng-morph'; 3 | 4 | describe('JSONFileContent', () => { 5 | it('should modify JSON', () => { 6 | const file = new JSONFileContent('{"some": {"path": []}}'); 7 | 8 | file.modify(['some', 'path', 0], {value: 3}); 9 | 10 | expect(file.getContent()).toBe(`{ 11 | "some": { 12 | "path": [ 13 | { 14 | "value": 3 15 | } 16 | ] 17 | } 18 | }`); 19 | }); 20 | 21 | it('should return a value', () => { 22 | const file = new JSONFileContent(`{ 23 | "some": { 24 | "path": [ 25 | { 26 | "value": 3 27 | } 28 | ] 29 | } 30 | }`); 31 | 32 | const value = file.get(['some', 'path', 0]); 33 | 34 | expect(value).toEqual({ 35 | value: 3, 36 | }); 37 | }); 38 | 39 | it('should remove a value', () => { 40 | const file = new JSONFileContent(`{ 41 | "some": { 42 | "path": [ 43 | { 44 | "value": 3 45 | } 46 | ] 47 | } 48 | }`); 49 | 50 | file.remove(['some', 'path', 0]); 51 | 52 | expect(file.getContent()).toBe(`{ 53 | "some": { 54 | "path": [] 55 | } 56 | }`); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/move-source-file-paths.spec.ts: -------------------------------------------------------------------------------- 1 | import {dasherize} from '@angular-devkit/core/src/utils/strings'; 2 | import {HostTree} from '@angular-devkit/schematics'; 3 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 4 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 5 | import { 6 | createProject, 7 | createSourceFile, 8 | getSourceFiles, 9 | moveSourceFilePaths, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('renameSourceFilePaths', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile('testFile.ts', "import {a} from './some/testFile'"); 24 | createSourceFile('some/testFile.ts', "export const a = 'b'"); 25 | createSourceFile('some/DeepPath/testFile.ts', ''); 26 | saveActiveProject(); 27 | 28 | moveSourceFilePaths(getSourceFiles('some/**/*.ts'), dasherize); 29 | saveActiveProject(); 30 | }); 31 | 32 | it('should change a file content', () => { 33 | expect(host.readContent('testFile.ts')).toBe( 34 | "import {a} from './some/test-file'", 35 | ); 36 | }); 37 | 38 | it('should exist renamed files', () => { 39 | expect(host.files).toEqual([ 40 | '/testFile.ts', 41 | '/some/test-file.ts', 42 | '/some/deep-path/test-file.ts', 43 | ]); 44 | }); 45 | 46 | afterEach(() => { 47 | resetActiveProject(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-accessors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getAccessors, 8 | getClasses, 9 | removeAccessors, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('removeAccessors', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class A { 27 | get getter(){} 28 | 29 | set setter(value){} 30 | } 31 | `, 32 | ); 33 | }); 34 | 35 | it('should remove accessors', () => { 36 | const declarations = getAccessors(getClasses('some/path/file.ts')); 37 | 38 | removeAccessors(declarations); 39 | 40 | saveActiveProject(); 41 | 42 | expect(host.readContent('some/path/file.ts')).toBe(` 43 | class A { 44 | } 45 | `); 46 | }); 47 | 48 | afterEach(() => { 49 | resetActiveProject(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-classes.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | removeClasses, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeClasses', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | class A {} 26 | 27 | const a: A; 28 | `, 29 | ); 30 | }); 31 | 32 | it('should remove classes', () => { 33 | removeClasses(getClasses('**/**', {name: 'A'})); 34 | 35 | saveActiveProject(); 36 | 37 | expect(host.readContent('some/path/file.ts')).toBe(` 38 | const a: A; 39 | `); 40 | }); 41 | 42 | afterEach(() => { 43 | resetActiveProject(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-constructors.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getConstructors, 9 | removeConstructors, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('removeConstructors', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class A { 27 | constructor(){ 28 | 29 | } 30 | } 31 | `, 32 | ); 33 | }); 34 | 35 | it('should remove constructors', () => { 36 | const declarations = getConstructors(getClasses('some/path/file.ts')); 37 | 38 | removeConstructors(declarations); 39 | 40 | saveActiveProject(); 41 | 42 | expect(host.readContent('some/path/file.ts')).toBe(` 43 | class A { 44 | } 45 | `); 46 | }); 47 | 48 | afterEach(() => { 49 | resetActiveProject(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-decorators.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getDecorators, 9 | removeDecorators, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('removeDecorators', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | @Decorator() 27 | class A {} 28 | `, 29 | ); 30 | }); 31 | 32 | it('should remove decorators', () => { 33 | const declarations = getDecorators(getClasses('some/path/file.ts')); 34 | 35 | removeDecorators(declarations); 36 | 37 | saveActiveProject(); 38 | 39 | expect(host.readContent('some/path/file.ts')).toBe(` 40 | class A {} 41 | `); 42 | }); 43 | 44 | afterEach(() => { 45 | resetActiveProject(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-enums.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getEnums, 8 | removeEnums, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeEnums', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile('some/path/file.ts', 'enum Test { }'); 23 | }); 24 | 25 | it('should remove enums', () => { 26 | const declarations = getEnums('some/path/file.ts', {name: 'Test'}); 27 | 28 | removeEnums(declarations); 29 | 30 | saveActiveProject(); 31 | 32 | expect(host.readContent('some/path/file.ts')).toBe(''); 33 | }); 34 | 35 | afterEach(() => { 36 | resetActiveProject(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-exports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getExports, 8 | removeExports, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeExports', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | export { a } from 'b'; 26 | 27 | console.log(a); 28 | `, 29 | ); 30 | }); 31 | 32 | it('should remove exports', () => { 33 | const exports = getExports('some/path/file.ts'); 34 | 35 | removeExports(exports); 36 | 37 | saveActiveProject(); 38 | 39 | expect(host.readContent('some/path/file.ts')).toBe(` 40 | console.log(a); 41 | `); 42 | }); 43 | 44 | afterEach(() => { 45 | resetActiveProject(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-functions.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getFunctions, 8 | removeFunctions, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeFunctions', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | function a(){ 26 | return 'a' 27 | } 28 | 29 | export function b() { 30 | return 'b' 31 | } 32 | `, 33 | ); 34 | }); 35 | 36 | it('should remove the `b` function', () => { 37 | removeFunctions(getFunctions('some/**/**.ts', {name: 'b'})); 38 | 39 | saveActiveProject(); 40 | 41 | expect(host.readContent('some/path/file.ts')).toBe(` 42 | function a(){ 43 | return 'a' 44 | } 45 | `); 46 | }); 47 | 48 | afterEach(() => { 49 | resetActiveProject(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-imports.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getImports, 8 | removeImports, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeImports', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile( 23 | 'some/path/file.ts', 24 | ` 25 | import { a } from 'b'; 26 | 27 | console.log(a); 28 | `, 29 | ); 30 | }); 31 | 32 | it('should remove imports', () => { 33 | const imports = getImports('some/path/file.ts'); 34 | 35 | removeImports(imports); 36 | 37 | saveActiveProject(); 38 | 39 | expect(host.readContent('some/path/file.ts')).toBe(` 40 | console.log(a); 41 | `); 42 | }); 43 | 44 | afterEach(() => { 45 | resetActiveProject(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-interfaces.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getInterfaces, 8 | removeInterfaces, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeInterfaces', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile('some/path/file.ts', 'interface A {}'); 23 | }); 24 | 25 | it('should remove Interfaces', () => { 26 | const declarations = getInterfaces('some/path/file.ts'); 27 | 28 | removeInterfaces(declarations); 29 | 30 | saveActiveProject(); 31 | 32 | expect(host.readContent('some/path/file.ts')).toBe(''); 33 | }); 34 | 35 | afterEach(() => { 36 | resetActiveProject(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-methods.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getMethods, 9 | removeMethods, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('removeMethods', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class B { 27 | test(){} 28 | } 29 | 30 | class A { 31 | test(){} 32 | } 33 | `, 34 | ); 35 | }); 36 | 37 | it('should remove methods', () => { 38 | const declarations = getMethods(getClasses('some/path/file.ts', {name: 'A'}), { 39 | name: 'test', 40 | }); 41 | 42 | removeMethods(declarations); 43 | 44 | saveActiveProject(); 45 | 46 | expect(host.readContent('some/path/file.ts')).toBe(` 47 | class B { 48 | test(){} 49 | } 50 | 51 | class A { 52 | } 53 | `); 54 | }); 55 | 56 | afterEach(() => { 57 | resetActiveProject(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-params.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getConstructors, 9 | getParams, 10 | removeParams, 11 | resetActiveProject, 12 | saveActiveProject, 13 | setActiveProject, 14 | } from 'ng-morph'; 15 | 16 | describe('removeParams', () => { 17 | let host: UnitTestTree; 18 | 19 | beforeEach(() => { 20 | host = new UnitTestTree(new HostTree()); 21 | 22 | setActiveProject(createProject(host)); 23 | 24 | createSourceFile( 25 | 'some/path/file.ts', 26 | ` 27 | class A { 28 | constructor(value1, value2 = 'defaultValue', value3){} 29 | } 30 | `, 31 | ); 32 | }); 33 | 34 | it('should remove params', () => { 35 | const declarations = getParams(getConstructors(getClasses('some/path/file.ts')), { 36 | initializer: "'defaultValue'", 37 | }); 38 | 39 | removeParams(declarations); 40 | 41 | saveActiveProject(); 42 | 43 | expect(host.readContent('some/path/file.ts')).toBe(` 44 | class A { 45 | constructor(value1, value3){} 46 | } 47 | `); 48 | }); 49 | 50 | afterEach(() => { 51 | resetActiveProject(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-properties.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getClasses, 8 | getProperties, 9 | removeProperties, 10 | resetActiveProject, 11 | saveActiveProject, 12 | setActiveProject, 13 | } from 'ng-morph'; 14 | 15 | describe('removeMethods', () => { 16 | let host: UnitTestTree; 17 | 18 | beforeEach(() => { 19 | host = new UnitTestTree(new HostTree()); 20 | 21 | setActiveProject(createProject(host)); 22 | 23 | createSourceFile( 24 | 'some/path/file.ts', 25 | ` 26 | class B { 27 | test = 'test' 28 | } 29 | 30 | class A { 31 | prop = 1; 32 | } 33 | `, 34 | ); 35 | }); 36 | 37 | it('should remove methods', () => { 38 | const declarations = getProperties(getClasses('some/path/file.ts', {name: 'B'}), { 39 | name: 'test', 40 | }); 41 | 42 | removeProperties(declarations); 43 | 44 | saveActiveProject(); 45 | 46 | expect(host.readContent('some/path/file.ts')).toBe(` 47 | class B { 48 | } 49 | 50 | class A { 51 | prop = 1; 52 | } 53 | `); 54 | }); 55 | 56 | afterEach(() => { 57 | resetActiveProject(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-type-aliases.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getTypeAliases, 8 | removeTypeAliases, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeTypeAliases', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile('some/path/file.ts', 'type A = string;'); 23 | }); 24 | 25 | it('should remove type aliases', () => { 26 | const declarations = getTypeAliases('some/path/file.ts'); 27 | 28 | removeTypeAliases(declarations); 29 | 30 | saveActiveProject(); 31 | 32 | expect(host.readContent('some/path/file.ts')).toBe(''); 33 | }); 34 | 35 | afterEach(() => { 36 | resetActiveProject(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /libs/ng-morph/tests/remove-variables.spec.ts: -------------------------------------------------------------------------------- 1 | import {HostTree} from '@angular-devkit/schematics'; 2 | import {UnitTestTree} from '@angular-devkit/schematics/testing'; 3 | import {afterEach, beforeEach, describe, expect, it} from '@jest/globals'; 4 | import { 5 | createProject, 6 | createSourceFile, 7 | getVariables, 8 | removeVariables, 9 | resetActiveProject, 10 | saveActiveProject, 11 | setActiveProject, 12 | } from 'ng-morph'; 13 | 14 | describe('removeVariables', () => { 15 | let host: UnitTestTree; 16 | 17 | beforeEach(() => { 18 | host = new UnitTestTree(new HostTree()); 19 | 20 | setActiveProject(createProject(host)); 21 | 22 | createSourceFile('some/path/file.ts', "const a = 'b'"); 23 | }); 24 | 25 | it('should remove variables', () => { 26 | const declarations = getVariables('some/path/file.ts'); 27 | 28 | removeVariables(declarations); 29 | 30 | saveActiveProject(); 31 | 32 | expect(host.readContent('some/path/file.ts')).toBe(''); 33 | }); 34 | 35 | afterEach(() => { 36 | resetActiveProject(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /libs/ng-morph/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "inlineSourceMap": true, 8 | "lib": ["esnext"], 9 | "types": ["node"] 10 | }, 11 | "exclude": ["**/*.spec.ts", "jest.config.ts"], 12 | "include": ["**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /libs/ng-morph/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "moduleResolution": "nodenext", 6 | "esModuleInterop": true, 7 | "types": ["jest", "node"] 8 | }, 9 | "include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasksRunnerOptions": { 3 | "default": { 4 | "options": { 5 | "canTrackAnalytics": false, 6 | "showUsageWarnings": true 7 | } 8 | } 9 | }, 10 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 11 | "targetDefaults": { 12 | "build": { 13 | "dependsOn": ["^build"], 14 | "inputs": ["production", "^production"], 15 | "cache": true 16 | }, 17 | "test": { 18 | "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"], 19 | "cache": true 20 | }, 21 | "lint": { 22 | "cache": true 23 | } 24 | }, 25 | "namedInputs": { 26 | "default": ["{projectRoot}/**/*", "sharedGlobals"], 27 | "sharedGlobals": [ 28 | "{workspaceRoot}/angular.json", 29 | "{workspaceRoot}/tsconfig.json", 30 | "{workspaceRoot}/tslint.json", 31 | "{workspaceRoot}/nx.json" 32 | ], 33 | "production": [ 34 | "default", 35 | "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", 36 | "!{projectRoot}/tsconfig.spec.json", 37 | "!{projectRoot}/jest.config.[jt]s" 38 | ] 39 | }, 40 | "defaultBase": "main" 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@taiga-ui/tsconfig", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "baseUrl": ".", 6 | "module": "esnext", 7 | "verbatimModuleSyntax": false, 8 | "typeRoots": ["node_modules/@types"], 9 | "paths": { 10 | "ng-morph": ["./libs/ng-morph/src/index.ts"], 11 | "rxjs": ["node_modules/rxjs"] 12 | } 13 | }, 14 | "exclude": ["node_modules", "tmp"] 15 | } 16 | --------------------------------------------------------------------------------