├── .eslintrc.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── build.yml │ ├── publish.yml │ ├── pull-request-lint.yml │ └── upgrade.yml ├── .gitignore ├── .mergify.yml ├── .npmignore ├── .projen ├── deps.json ├── files.json └── tasks.json ├── .projenrc.ts ├── .vscode └── launch.json ├── .vscodeignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── resources ├── dark │ └── projen-outline.svg ├── light │ └── projen-outline.svg ├── projen.png └── projen.svg ├── screenshots ├── files.png ├── overview.png ├── project-types.png └── tasks.png ├── src ├── extension.ts ├── generated_file_decorator.ts ├── jsii │ └── fetcher.ts ├── project │ ├── project_type.ts │ └── vscode_types.ts ├── projen_info.ts ├── projen_view.ts └── projen_watcher.ts ├── test ├── other-sample-node-project │ ├── .gitattributes │ ├── .github │ │ ├── pull_request_template.md │ │ └── workflows │ │ │ ├── build.yml │ │ │ ├── pull-request-lint.yml │ │ │ ├── release.yml │ │ │ ├── stale.yml │ │ │ └── upgrade-main.yml │ ├── .gitignore │ ├── .mergify.yml │ ├── .npmignore │ ├── .projen │ │ ├── deps.json │ │ ├── files.json │ │ └── tasks.json │ ├── .projenrc.js │ ├── LICENSE │ ├── README.md │ ├── package-lock.json │ └── package.json └── sample-node-project │ ├── .gitattributes │ ├── .github │ ├── pull_request_template.md │ └── workflows │ │ ├── build.yml │ │ ├── pull-request-lint.yml │ │ ├── release.yml │ │ └── upgrade-main.yml │ ├── .gitignore │ ├── .mergify.yml │ ├── .npmignore │ ├── .projen │ ├── deps.json │ ├── files.json │ └── tasks.json │ ├── .projenrc.js │ ├── LICENSE │ ├── README.md │ ├── package-lock.json │ └── package.json ├── tsconfig.dev.json └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "env": { 4 | "jest": true, 5 | "node": true 6 | }, 7 | "root": true, 8 | "plugins": [ 9 | "@typescript-eslint", 10 | "import" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaVersion": 2018, 15 | "sourceType": "module", 16 | "project": "./tsconfig.dev.json" 17 | }, 18 | "extends": [ 19 | "plugin:import/typescript", 20 | "plugin:prettier/recommended" 21 | ], 22 | "settings": { 23 | "import/parsers": { 24 | "@typescript-eslint/parser": [ 25 | ".ts", 26 | ".tsx" 27 | ] 28 | }, 29 | "import/resolver": { 30 | "node": {}, 31 | "typescript": { 32 | "project": "./tsconfig.dev.json", 33 | "alwaysTryTypes": true 34 | } 35 | } 36 | }, 37 | "ignorePatterns": [ 38 | "*.js", 39 | "*.d.ts", 40 | "node_modules/", 41 | "*.generated.ts", 42 | "coverage", 43 | "!.projenrc.ts", 44 | "!projenrc/**/*.ts" 45 | ], 46 | "rules": { 47 | "@typescript-eslint/no-require-imports": [ 48 | "error" 49 | ], 50 | "import/no-extraneous-dependencies": [ 51 | "error", 52 | { 53 | "devDependencies": [ 54 | "**/test/**", 55 | ".projenrc.ts", 56 | "projenrc/**/*.ts" 57 | ], 58 | "optionalDependencies": false, 59 | "peerDependencies": true 60 | } 61 | ], 62 | "import/no-unresolved": [ 63 | "error" 64 | ], 65 | "import/order": [ 66 | "warn", 67 | { 68 | "groups": [ 69 | "builtin", 70 | "external" 71 | ], 72 | "alphabetize": { 73 | "order": "asc", 74 | "caseInsensitive": true 75 | } 76 | } 77 | ], 78 | "no-duplicate-imports": [ 79 | "error" 80 | ], 81 | "no-shadow": [ 82 | "off" 83 | ], 84 | "@typescript-eslint/no-shadow": [ 85 | "error" 86 | ], 87 | "key-spacing": [ 88 | "error" 89 | ], 90 | "no-multiple-empty-lines": [ 91 | "error" 92 | ], 93 | "@typescript-eslint/no-floating-promises": [ 94 | "error" 95 | ], 96 | "no-return-await": [ 97 | "off" 98 | ], 99 | "@typescript-eslint/return-await": [ 100 | "error" 101 | ], 102 | "no-trailing-spaces": [ 103 | "error" 104 | ], 105 | "dot-notation": [ 106 | "error" 107 | ], 108 | "no-bitwise": [ 109 | "error" 110 | ], 111 | "@typescript-eslint/member-ordering": [ 112 | "error", 113 | { 114 | "default": [ 115 | "public-static-field", 116 | "public-static-method", 117 | "protected-static-field", 118 | "protected-static-method", 119 | "private-static-field", 120 | "private-static-method", 121 | "field", 122 | "constructor", 123 | "method" 124 | ] 125 | } 126 | ] 127 | }, 128 | "overrides": [ 129 | { 130 | "files": [ 131 | ".projenrc.ts" 132 | ], 133 | "rules": { 134 | "@typescript-eslint/no-require-imports": "off", 135 | "import/no-extraneous-dependencies": "off" 136 | } 137 | } 138 | ] 139 | } 140 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | *.snap linguist-generated 4 | /.eslintrc.json linguist-generated 5 | /.gitattributes linguist-generated 6 | /.github/pull_request_template.md linguist-generated 7 | /.github/workflows/build.yml linguist-generated 8 | /.github/workflows/publish.yml linguist-generated 9 | /.github/workflows/pull-request-lint.yml linguist-generated 10 | /.github/workflows/upgrade.yml linguist-generated 11 | /.gitignore linguist-generated 12 | /.mergify.yml linguist-generated 13 | /.npmignore linguist-generated 14 | /.projen/** linguist-generated 15 | /.projen/deps.json linguist-generated 16 | /.projen/files.json linguist-generated 17 | /.projen/tasks.json linguist-generated 18 | /.vscodeignore linguist-generated 19 | /LICENSE linguist-generated 20 | /package-lock.json linguist-generated 21 | /package.json linguist-generated 22 | /tsconfig.dev.json linguist-generated 23 | /tsconfig.json linguist-generated -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '[Bug] Short description goes here' 5 | labels: ['bug'] 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **OS** 27 | e.g. Windows, Mac, Linux 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '[Feature] Title of feature request goes here' 5 | labels: ['feature'] 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: build 4 | on: 5 | pull_request: {} 6 | workflow_dispatch: {} 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: write 12 | outputs: 13 | self_mutation_happened: ${{ steps.self_mutation.outputs.self_mutation_happened }} 14 | env: 15 | CI: "true" 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | with: 20 | ref: ${{ github.event.pull_request.head.ref }} 21 | repository: ${{ github.event.pull_request.head.repo.full_name }} 22 | - name: Setup Node.js 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: 20.0.0 26 | - name: Install dependencies 27 | run: npm install 28 | - name: build 29 | run: npx projen build 30 | - name: Find mutations 31 | id: self_mutation 32 | run: |- 33 | git add . 34 | git diff --staged --patch --exit-code > .repo.patch || echo "self_mutation_happened=true" >> $GITHUB_OUTPUT 35 | working-directory: ./ 36 | - name: Upload patch 37 | if: steps.self_mutation.outputs.self_mutation_happened 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: .repo.patch 41 | path: .repo.patch 42 | overwrite: true 43 | - name: Fail build on mutation 44 | if: steps.self_mutation.outputs.self_mutation_happened 45 | run: |- 46 | echo "::error::Files were changed during build (see build log). If this was triggered from a fork, you will need to update your branch." 47 | cat .repo.patch 48 | exit 1 49 | self-mutation: 50 | needs: build 51 | runs-on: ubuntu-latest 52 | permissions: 53 | contents: write 54 | if: always() && needs.build.outputs.self_mutation_happened && !(github.event.pull_request.head.repo.full_name != github.repository) 55 | steps: 56 | - name: Checkout 57 | uses: actions/checkout@v4 58 | with: 59 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 60 | ref: ${{ github.event.pull_request.head.ref }} 61 | repository: ${{ github.event.pull_request.head.repo.full_name }} 62 | - name: Download patch 63 | uses: actions/download-artifact@v4 64 | with: 65 | name: .repo.patch 66 | path: ${{ runner.temp }} 67 | - name: Apply patch 68 | run: '[ -s ${{ runner.temp }}/.repo.patch ] && git apply ${{ runner.temp }}/.repo.patch || echo "Empty patch. Skipping."' 69 | - name: Set git identity 70 | run: |- 71 | git config user.name "github-actions" 72 | git config user.email "github-actions@github.com" 73 | - name: Push changes 74 | env: 75 | PULL_REQUEST_REF: ${{ github.event.pull_request.head.ref }} 76 | run: |- 77 | git add . 78 | git commit -s -m "chore: self mutation" 79 | git push origin HEAD:$PULL_REQUEST_REF 80 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: Publish 4 | on: 5 | push: 6 | branches: 7 | - master 8 | workflow_dispatch: {} 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | outputs: 15 | latest_commit: ${{ steps.git_remote.outputs.latest_commit }} 16 | tag_exists: ${{ steps.check_tag_exists.outputs.exists }} 17 | env: 18 | CI: "true" 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | - name: Set git identity 25 | run: |- 26 | git config user.name "github-actions" 27 | git config user.email "github-actions@github.com" 28 | - name: release 29 | run: npx projen release 30 | - name: Check if version has already been tagged 31 | id: check_tag_exists 32 | run: |- 33 | TAG=$(cat dist/releasetag.txt) 34 | ([ ! -z "$TAG" ] && git ls-remote -q --exit-code --tags origin $TAG && (echo "exists=true" >> $GITHUB_OUTPUT)) || (echo "exists=false" >> $GITHUB_OUTPUT) 35 | cat $GITHUB_OUTPUT 36 | - name: Check for new commits 37 | id: git_remote 38 | run: |- 39 | echo "latest_commit=$(git ls-remote origin -h ${{ github.ref }} | cut -f1)" >> $GITHUB_OUTPUT 40 | cat $GITHUB_OUTPUT 41 | - name: Backup artifact permissions 42 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} 43 | run: cd dist && getfacl -R . > permissions-backup.acl 44 | continue-on-error: true 45 | - name: Upload artifact 46 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: build-artifact 50 | path: dist 51 | overwrite: true 52 | release_github: 53 | name: Publish to GitHub Releases 54 | needs: release 55 | runs-on: ubuntu-latest 56 | permissions: 57 | contents: write 58 | if: needs.release.outputs.tag_exists != 'true' && needs.release.outputs.latest_commit == github.sha 59 | steps: 60 | - uses: actions/setup-node@v4 61 | with: 62 | node-version: 18.x 63 | - name: Download build artifacts 64 | uses: actions/download-artifact@v4 65 | with: 66 | name: build-artifact 67 | path: dist 68 | - name: Restore build artifact permissions 69 | run: cd dist && setfacl --restore=permissions-backup.acl 70 | continue-on-error: true 71 | - name: Release 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | GITHUB_REPOSITORY: ${{ github.repository }} 75 | GITHUB_REF: ${{ github.sha }} 76 | run: errout=$(mktemp); gh release create $(cat dist/releasetag.txt) -R $GITHUB_REPOSITORY -F dist/changelog.md -t $(cat dist/releasetag.txt) --target $GITHUB_REF 2> $errout && true; exitcode=$?; if [ $exitcode -ne 0 ] && ! grep -q "Release.tag_name already exists" $errout; then cat $errout; exit $exitcode; fi 77 | release_marketplace: 78 | name: Publish Extension 79 | needs: release_github 80 | runs-on: ubuntu-latest 81 | permissions: 82 | contents: read 83 | steps: 84 | - name: Download build artifacts 85 | uses: actions/download-artifact@v4 86 | with: 87 | name: build-artifact 88 | path: dist 89 | - name: Publish to VS Marketplace 90 | uses: HaaLeo/publish-vscode-extension@v1 91 | with: 92 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 93 | registryUrl: https://marketplace.visualstudio.com 94 | extensionFile: ./dist/extension.vsix 95 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | jobs: 14 | validate: 15 | name: Validate PR title 16 | runs-on: ubuntu-latest 17 | permissions: 18 | pull-requests: write 19 | steps: 20 | - uses: amannn/action-semantic-pull-request@v5.4.0 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | types: |- 25 | feat 26 | fix 27 | chore 28 | requireScope: false 29 | -------------------------------------------------------------------------------- /.github/workflows/upgrade.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: upgrade 4 | on: 5 | workflow_dispatch: {} 6 | schedule: 7 | - cron: 0 0 * * * 8 | jobs: 9 | upgrade: 10 | name: Upgrade 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: read 14 | outputs: 15 | patch_created: ${{ steps.create_patch.outputs.patch_created }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | - name: Setup Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: 20.0.0 23 | - name: Install dependencies 24 | run: npm ci 25 | - name: Upgrade dependencies 26 | run: npx projen upgrade 27 | - name: Find mutations 28 | id: create_patch 29 | run: |- 30 | git add . 31 | git diff --staged --patch --exit-code > .repo.patch || echo "patch_created=true" >> $GITHUB_OUTPUT 32 | working-directory: ./ 33 | - name: Upload patch 34 | if: steps.create_patch.outputs.patch_created 35 | uses: actions/upload-artifact@v4 36 | with: 37 | name: .repo.patch 38 | path: .repo.patch 39 | overwrite: true 40 | pr: 41 | name: Create Pull Request 42 | needs: upgrade 43 | runs-on: ubuntu-latest 44 | permissions: 45 | contents: read 46 | if: ${{ needs.upgrade.outputs.patch_created }} 47 | steps: 48 | - name: Checkout 49 | uses: actions/checkout@v4 50 | - name: Download patch 51 | uses: actions/download-artifact@v4 52 | with: 53 | name: .repo.patch 54 | path: ${{ runner.temp }} 55 | - name: Apply patch 56 | run: '[ -s ${{ runner.temp }}/.repo.patch ] && git apply ${{ runner.temp }}/.repo.patch || echo "Empty patch. Skipping."' 57 | - name: Set git identity 58 | run: |- 59 | git config user.name "github-actions" 60 | git config user.email "github-actions@github.com" 61 | - name: Create Pull Request 62 | id: create-pr 63 | uses: peter-evans/create-pull-request@v6 64 | with: 65 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 66 | commit-message: |- 67 | chore(deps): upgrade dependencies 68 | 69 | Upgrades project dependencies. See details in [workflow run]. 70 | 71 | [Workflow Run]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 72 | 73 | ------ 74 | 75 | *Automatically created by projen via the "upgrade" workflow* 76 | branch: github-actions/upgrade 77 | title: "chore(deps): upgrade dependencies" 78 | body: |- 79 | Upgrades project dependencies. See details in [workflow run]. 80 | 81 | [Workflow Run]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 82 | 83 | ------ 84 | 85 | *Automatically created by projen via the "upgrade" workflow* 86 | author: github-actions 87 | committer: github-actions 88 | signoff: true 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | !/.gitattributes 3 | !/.projen/tasks.json 4 | !/.projen/deps.json 5 | !/.projen/files.json 6 | !/.github/workflows/pull-request-lint.yml 7 | !/package.json 8 | !/LICENSE 9 | !/.npmignore 10 | logs 11 | *.log 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | lerna-debug.log* 16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | lib-cov 22 | coverage 23 | *.lcov 24 | .nyc_output 25 | build/Release 26 | node_modules/ 27 | jspm_packages/ 28 | *.tsbuildinfo 29 | .eslintcache 30 | *.tgz 31 | .yarn-integrity 32 | .cache 33 | /test-reports/ 34 | junit.xml 35 | /coverage/ 36 | !/.github/workflows/build.yml 37 | !/.mergify.yml 38 | !/.github/workflows/upgrade.yml 39 | !/.github/pull_request_template.md 40 | !/test/ 41 | !/tsconfig.json 42 | !/tsconfig.dev.json 43 | !/src/ 44 | /lib 45 | /dist/ 46 | !/.eslintrc.json 47 | !/.vscodeignore 48 | out 49 | *.vsix 50 | .vscode-test 51 | /dist/changelog.md 52 | /dist/version.txt 53 | !/.github/workflows/publish.yml 54 | !/.projenrc.ts 55 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | queue_rules: 4 | - name: default 5 | update_method: merge 6 | conditions: 7 | - "#approved-reviews-by>=1" 8 | - -label~=(do-not-merge) 9 | - status-success=build 10 | pull_request_rules: 11 | - name: Automatic merge on approval and successful build 12 | actions: 13 | delete_head_branch: {} 14 | queue: 15 | method: squash 16 | name: default 17 | commit_message_template: |- 18 | {{ title }} (#{{ number }}) 19 | 20 | {{ body }} 21 | conditions: 22 | - "#approved-reviews-by>=1" 23 | - -label~=(do-not-merge) 24 | - status-success=build 25 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | /.projen/ 3 | /test-reports/ 4 | junit.xml 5 | /coverage/ 6 | permissions-backup.acl 7 | /.mergify.yml 8 | /test/ 9 | /tsconfig.dev.json 10 | /src/ 11 | !/lib/ 12 | !/lib/**/*.js 13 | !/lib/**/*.d.ts 14 | dist 15 | /tsconfig.json 16 | /.github/ 17 | /.vscode/ 18 | /.idea/ 19 | /.projenrc.js 20 | tsconfig.tsbuildinfo 21 | /.eslintrc.json 22 | /dist/changelog.md 23 | /dist/version.txt 24 | /.gitattributes 25 | /.projenrc.ts 26 | /projenrc 27 | -------------------------------------------------------------------------------- /.projen/deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "@types/gunzip-maybe", 5 | "type": "build" 6 | }, 7 | { 8 | "name": "@types/jest", 9 | "type": "build" 10 | }, 11 | { 12 | "name": "@types/node", 13 | "version": "^20", 14 | "type": "build" 15 | }, 16 | { 17 | "name": "@types/pacote", 18 | "type": "build" 19 | }, 20 | { 21 | "name": "@types/tar-stream", 22 | "type": "build" 23 | }, 24 | { 25 | "name": "@typescript-eslint/eslint-plugin", 26 | "version": "^6", 27 | "type": "build" 28 | }, 29 | { 30 | "name": "@typescript-eslint/parser", 31 | "version": "^6", 32 | "type": "build" 33 | }, 34 | { 35 | "name": "@vscode/vsce", 36 | "type": "build" 37 | }, 38 | { 39 | "name": "constructs", 40 | "version": "^10.0.0", 41 | "type": "build" 42 | }, 43 | { 44 | "name": "esbuild", 45 | "type": "build" 46 | }, 47 | { 48 | "name": "eslint-config-prettier", 49 | "type": "build" 50 | }, 51 | { 52 | "name": "eslint-import-resolver-typescript", 53 | "type": "build" 54 | }, 55 | { 56 | "name": "eslint-plugin-import", 57 | "type": "build" 58 | }, 59 | { 60 | "name": "eslint-plugin-prettier", 61 | "type": "build" 62 | }, 63 | { 64 | "name": "eslint", 65 | "version": "^8", 66 | "type": "build" 67 | }, 68 | { 69 | "name": "jest", 70 | "type": "build" 71 | }, 72 | { 73 | "name": "jest-junit", 74 | "version": "^15", 75 | "type": "build" 76 | }, 77 | { 78 | "name": "prettier", 79 | "type": "build" 80 | }, 81 | { 82 | "name": "projen", 83 | "type": "build" 84 | }, 85 | { 86 | "name": "shx", 87 | "type": "build" 88 | }, 89 | { 90 | "name": "ts-jest", 91 | "type": "build" 92 | }, 93 | { 94 | "name": "ts-node", 95 | "type": "build" 96 | }, 97 | { 98 | "name": "typescript", 99 | "type": "build" 100 | }, 101 | { 102 | "name": "@types/vscode", 103 | "type": "runtime" 104 | }, 105 | { 106 | "name": "gunzip-maybe", 107 | "type": "runtime" 108 | }, 109 | { 110 | "name": "pacote", 111 | "type": "runtime" 112 | }, 113 | { 114 | "name": "registry-url", 115 | "type": "runtime" 116 | }, 117 | { 118 | "name": "tar-stream", 119 | "type": "runtime" 120 | } 121 | ], 122 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 123 | } 124 | -------------------------------------------------------------------------------- /.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".eslintrc.json", 4 | ".gitattributes", 5 | ".github/pull_request_template.md", 6 | ".github/workflows/build.yml", 7 | ".github/workflows/publish.yml", 8 | ".github/workflows/pull-request-lint.yml", 9 | ".github/workflows/upgrade.yml", 10 | ".gitignore", 11 | ".mergify.yml", 12 | ".npmignore", 13 | ".projen/deps.json", 14 | ".projen/files.json", 15 | ".projen/tasks.json", 16 | ".vscodeignore", 17 | "LICENSE", 18 | "tsconfig.dev.json", 19 | "tsconfig.json" 20 | ], 21 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 22 | } 23 | -------------------------------------------------------------------------------- /.projen/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "build": { 4 | "name": "build", 5 | "description": "Full release build", 6 | "steps": [ 7 | { 8 | "spawn": "default" 9 | }, 10 | { 11 | "spawn": "pre-compile" 12 | }, 13 | { 14 | "spawn": "compile" 15 | }, 16 | { 17 | "spawn": "post-compile" 18 | }, 19 | { 20 | "spawn": "test" 21 | }, 22 | { 23 | "spawn": "package" 24 | } 25 | ] 26 | }, 27 | "bump": { 28 | "name": "bump", 29 | "description": "Bumps version based on latest git tag and generates a changelog entry", 30 | "env": { 31 | "OUTFILE": "package.json", 32 | "CHANGELOG": "dist/changelog.md", 33 | "BUMPFILE": "dist/version.txt", 34 | "RELEASETAG": "dist/releasetag.txt", 35 | "RELEASE_TAG_PREFIX": "" 36 | }, 37 | "steps": [ 38 | { 39 | "builtin": "release/bump-version" 40 | } 41 | ], 42 | "condition": "! git log --oneline -1 | grep -q \"chore(release):\"" 43 | }, 44 | "clobber": { 45 | "name": "clobber", 46 | "description": "hard resets to HEAD of origin and cleans the local repo", 47 | "env": { 48 | "BRANCH": "$(git branch --show-current)" 49 | }, 50 | "steps": [ 51 | { 52 | "exec": "git checkout -b scratch", 53 | "name": "save current HEAD in \"scratch\" branch" 54 | }, 55 | { 56 | "exec": "git checkout $BRANCH" 57 | }, 58 | { 59 | "exec": "git fetch origin", 60 | "name": "fetch latest changes from origin" 61 | }, 62 | { 63 | "exec": "git reset --hard origin/$BRANCH", 64 | "name": "hard reset to origin commit" 65 | }, 66 | { 67 | "exec": "git clean -fdx", 68 | "name": "clean all untracked files" 69 | }, 70 | { 71 | "say": "ready to rock! (unpushed commits are under the \"scratch\" branch)" 72 | } 73 | ], 74 | "condition": "git diff --exit-code > /dev/null" 75 | }, 76 | "compile": { 77 | "name": "compile", 78 | "description": "Only compile", 79 | "steps": [ 80 | { 81 | "exec": "tsc --noEmit" 82 | }, 83 | { 84 | "exec": "esbuild ./src/extension.ts --outfile=lib/extension.js --external:node-gyp --external:vscode --format=cjs --platform=node --bundle" 85 | } 86 | ] 87 | }, 88 | "default": { 89 | "name": "default", 90 | "description": "Synthesize project files", 91 | "steps": [ 92 | { 93 | "exec": "ts-node --project tsconfig.dev.json .projenrc.ts" 94 | } 95 | ] 96 | }, 97 | "eject": { 98 | "name": "eject", 99 | "description": "Remove projen from the project", 100 | "env": { 101 | "PROJEN_EJECTING": "true" 102 | }, 103 | "steps": [ 104 | { 105 | "spawn": "default" 106 | } 107 | ] 108 | }, 109 | "eslint": { 110 | "name": "eslint", 111 | "description": "Runs eslint against the codebase", 112 | "steps": [ 113 | { 114 | "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern $@ src test projenrc .projenrc.ts", 115 | "receiveArgs": true 116 | } 117 | ] 118 | }, 119 | "install": { 120 | "name": "install", 121 | "description": "Install project dependencies and update lockfile (non-frozen)", 122 | "steps": [ 123 | { 124 | "exec": "npm install" 125 | } 126 | ] 127 | }, 128 | "install:ci": { 129 | "name": "install:ci", 130 | "description": "Install project dependencies using frozen lockfile", 131 | "steps": [ 132 | { 133 | "exec": "npm ci" 134 | } 135 | ] 136 | }, 137 | "package": { 138 | "name": "package", 139 | "description": "Creates the distribution package", 140 | "steps": [ 141 | { 142 | "exec": "mkdir -p dist" 143 | }, 144 | { 145 | "exec": "esbuild ./src/extension.ts --outfile=lib/extension.js --external:node-gyp --external:vscode --format=cjs --platform=node --bundle --minify" 146 | }, 147 | { 148 | "exec": "vsce package -o dist/extension.vsix" 149 | } 150 | ] 151 | }, 152 | "post-compile": { 153 | "name": "post-compile", 154 | "description": "Runs after successful compilation" 155 | }, 156 | "post-upgrade": { 157 | "name": "post-upgrade", 158 | "description": "Runs after upgrading dependencies" 159 | }, 160 | "pre-compile": { 161 | "name": "pre-compile", 162 | "description": "Prepare the project for compilation" 163 | }, 164 | "release": { 165 | "name": "release", 166 | "description": "Prepare a release from \"master\" branch", 167 | "env": { 168 | "RELEASE": "true" 169 | }, 170 | "steps": [ 171 | { 172 | "exec": "npm ci" 173 | }, 174 | { 175 | "exec": "rm -fr dist" 176 | }, 177 | { 178 | "spawn": "bump" 179 | }, 180 | { 181 | "spawn": "build" 182 | }, 183 | { 184 | "spawn": "unbump" 185 | }, 186 | { 187 | "exec": "git diff --ignore-space-at-eol --exit-code" 188 | } 189 | ] 190 | }, 191 | "test": { 192 | "name": "test", 193 | "description": "Run tests", 194 | "steps": [ 195 | { 196 | "exec": "jest --passWithNoTests --coverageProvider=v8 --updateSnapshot", 197 | "receiveArgs": true 198 | }, 199 | { 200 | "spawn": "eslint" 201 | } 202 | ] 203 | }, 204 | "test:watch": { 205 | "name": "test:watch", 206 | "description": "Run jest in watch mode", 207 | "steps": [ 208 | { 209 | "exec": "jest --watch" 210 | } 211 | ] 212 | }, 213 | "unbump": { 214 | "name": "unbump", 215 | "description": "Restores version to 0.0.0", 216 | "env": { 217 | "OUTFILE": "package.json", 218 | "CHANGELOG": "dist/changelog.md", 219 | "BUMPFILE": "dist/version.txt", 220 | "RELEASETAG": "dist/releasetag.txt", 221 | "RELEASE_TAG_PREFIX": "" 222 | }, 223 | "steps": [ 224 | { 225 | "builtin": "release/reset-version" 226 | } 227 | ] 228 | }, 229 | "upgrade": { 230 | "name": "upgrade", 231 | "description": "upgrade dependencies", 232 | "env": { 233 | "CI": "0" 234 | }, 235 | "steps": [ 236 | { 237 | "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --dep=dev,peer,prod,optional --filter=@types/gunzip-maybe,@types/jest,@types/pacote,@types/tar-stream,@vscode/vsce,esbuild,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-prettier,jest,prettier,projen,shx,ts-jest,ts-node,typescript,@types/vscode,gunzip-maybe,pacote,registry-url,tar-stream" 238 | }, 239 | { 240 | "exec": "npm install" 241 | }, 242 | { 243 | "exec": "npm update @types/gunzip-maybe @types/jest @types/node @types/pacote @types/tar-stream @typescript-eslint/eslint-plugin @typescript-eslint/parser @vscode/vsce constructs esbuild eslint-config-prettier eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-prettier eslint jest jest-junit prettier projen shx ts-jest ts-node typescript @types/vscode gunzip-maybe pacote registry-url tar-stream" 244 | }, 245 | { 246 | "exec": "npx projen" 247 | }, 248 | { 249 | "spawn": "post-upgrade" 250 | } 251 | ] 252 | }, 253 | "watch": { 254 | "name": "watch", 255 | "description": "Watch & compile in the background", 256 | "steps": [ 257 | { 258 | "exec": "tsc --build -w" 259 | } 260 | ] 261 | } 262 | }, 263 | "env": { 264 | "PATH": "$(npx -c \"node --print process.env.PATH\")" 265 | }, 266 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 267 | } 268 | -------------------------------------------------------------------------------- /.projenrc.ts: -------------------------------------------------------------------------------- 1 | import { NodePackageManager } from "projen/lib/javascript"; 2 | import { VSCodeExtensionProject } from "./src/project/project_type"; 3 | 4 | const project = new VSCodeExtensionProject({ 5 | defaultReleaseBranch: "master", 6 | name: "vscode-projen", 7 | packageManager: NodePackageManager.NPM, 8 | repository: "https://github.com/MarkMcCulloh/vscode-projen.git", 9 | projenrcTs: true, 10 | entrypoint: "./lib/extension.js", 11 | minNodeVersion: "20.0.0", 12 | deps: ["gunzip-maybe", "tar-stream", "pacote", "registry-url"], 13 | devDeps: ["shx", "@types/gunzip-maybe", "@types/tar-stream", "@types/pacote"], 14 | eslintOptions: { 15 | dirs: ["src"], 16 | devdirs: ["test"], 17 | prettier: true, 18 | }, 19 | tsconfig: { 20 | compilerOptions: { 21 | lib: ["es2021", "dom"], 22 | }, 23 | }, 24 | // TODO: Figure out a way to avoid "onStartupFinished" 25 | // This is needed to allow bootstrapping projen in an empty workspace 26 | activationEvents: [ 27 | "workspaceContains:.projen/**", 28 | "onView:projen", 29 | "onStartupFinished", 30 | ], 31 | contributes: { 32 | configuration: { 33 | title: "Projen", 34 | properties: { 35 | "projen.projects.externalLibraries": { 36 | type: "string", 37 | editPresentation: "multilineText", 38 | default: "", 39 | description: 40 | "When creating a new project, these external libraries will show as options.\nSeparate with newlines.\nMay use `|` after library name to add documentation (e.g. `vue-projen | Vue templates`).", 41 | }, 42 | "projen.tasks.executeInTerminal": { 43 | type: "boolean", 44 | default: false, 45 | description: 46 | "When running a task, use the integrated terminal instead of the special task window.", 47 | }, 48 | "projen.terminal.alwaysChangeToWorkspaceDirectory": { 49 | type: "boolean", 50 | default: true, 51 | description: 52 | "Before running each command in the integrated terminal, always change the directory to the root.", 53 | }, 54 | "projen.managedFiles.decoration.enable": { 55 | type: "boolean", 56 | default: true, 57 | description: "Label and darken projen-managed files in the explorer.", 58 | }, 59 | "projen.managedFiles.decoration.badge": { 60 | type: "string", 61 | default: "PJ", 62 | description: 63 | "MUST BE < 3 CHARACTERS.\nText of the label applied to managed projen files. Can leave empty to remove.", 64 | }, 65 | "projen.managedFiles.decoration.themeColor": { 66 | type: "string", 67 | default: "gitDecoration.ignoredResourceForeground", 68 | description: 69 | "ThemeColor id to apply to managed files. Leave empty to not apply any color.", 70 | }, 71 | }, 72 | }, 73 | taskDefinitions: [ 74 | { 75 | type: "projen", 76 | required: ["task"], 77 | when: "shellExecutionSupported && projen.inProject", 78 | properties: { 79 | task: { 80 | type: "string", 81 | description: "The projen task to execute", 82 | }, 83 | }, 84 | }, 85 | ], 86 | viewsContainers: { 87 | activitybar: [ 88 | { 89 | id: "projen", 90 | title: "Projen", 91 | icon: "resources/dark/projen-outline.svg", 92 | }, 93 | ], 94 | }, 95 | views: { 96 | projen: [ 97 | { 98 | id: "projenProjects", 99 | name: "Projects", 100 | }, 101 | ], 102 | }, 103 | commands: [ 104 | { 105 | command: "projen.run", 106 | title: "Run Projen", 107 | icon: { 108 | light: "resources/light/projen-outline.svg", 109 | dark: "resources/dark/projen-outline.svg", 110 | }, 111 | }, 112 | { 113 | command: "projen.runTask", 114 | title: "Run Projen Task", 115 | icon: "$(play)", 116 | }, 117 | { 118 | command: "projen.openProjenRc", 119 | title: "Open Projen File", 120 | icon: "$(gear)", 121 | }, 122 | { 123 | command: "projen.new", 124 | title: "Generate Projen Project", 125 | }, 126 | ], 127 | menus: { 128 | "view/title": [ 129 | { 130 | command: "projen.run", 131 | group: "navigation", 132 | when: "projen.inProject == true && view == projenProjects", 133 | }, 134 | { 135 | command: "projen.openProjenRc", 136 | group: "navigation", 137 | when: "projen.inProject == true && view == projenProjects", 138 | }, 139 | { 140 | command: "projen.run", 141 | group: "navigation", 142 | when: "projen.inProject == true && activeViewlet == 'workbench.view.explorer'", 143 | }, 144 | { 145 | command: "projen.openProjenRc", 146 | group: "navigation", 147 | when: "projen.inProject == true && activeViewlet == 'workbench.view.explorer'", 148 | }, 149 | ], 150 | }, 151 | }, 152 | displayName: "Projen", 153 | icon: "resources/projen.png", 154 | publishToVSMarketplace: true, 155 | // Disabled for now https://github.com/MarkMcCulloh/vscode-projen/issues/29 156 | publishToOpenVSXRegistry: false, 157 | vscodeVersion: "^1.62.0", 158 | description: "Projen helpers and utilities", 159 | publisher: "MarkMcCulloh", 160 | preview: false, 161 | jest: true, 162 | }); 163 | 164 | project.vscodeIgnore!.addPatterns("!node_modules/node-gyp/bin/node-gyp.js"); 165 | 166 | project.addFields({ 167 | browser: "./lib/extension.js", 168 | }); 169 | 170 | project.addExcludeFromCleanup("test/**"); 171 | 172 | project.synth(); 173 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": ["--disable-extensions", "--extensionDevelopmentPath=${workspaceFolder}", "${workspaceFolder}/test/sample-node-project"], 13 | "outFiles": ["${workspaceFolder}/lib/**/*.js"] 14 | // "preLaunchTask": "npm: build" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | .vscode/** 3 | .vscode-test/** 4 | src/** 5 | .gitignore 6 | **/tsconfig.json 7 | **/.eslintrc.json 8 | **/*.map 9 | **/*.ts 10 | node_modules/ 11 | dist/ 12 | test/ 13 | test-reports/ 14 | coverage/ 15 | .projen/ 16 | !node_modules/node-gyp/bin/node-gyp.js 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Projen + VSCode = 💖 2 | 3 | Add some [projen](https://github.com/projen/projen) flavor to VSCode! 4 | 5 | ## Features 6 | 7 | - Commands 8 | - Run projen 9 | - Run tasks 10 | - Generate new project 11 | - Generate new project from external type 12 | - Task List 13 | - Run tasks in list with a click 14 | - List steps and subtasks (and their steps too) 15 | - Dependency List 16 | - List packages with types and pinned versions 17 | - Managed Files/Folders 18 | - Show list of files managed by projen (either directly or indirectly, like a lockfile) 19 | - De-emphasize files managed by projen in explorer and decorate it with a "PJ" badge 20 | 21 | ## Changelog 22 | 23 | Changelog is kept via [GitHub Releases](https://github.com/MarkMcCulloh/vscode-projen/releases). 24 | 25 | ## Screenshots 26 | 27 | ![Basic Overview](./screenshots/overview.png) 28 | 29 | ![Files](./screenshots/files.png) 30 | 31 | ![Tasks](./screenshots/tasks.png) 32 | 33 | ![Project Types](./screenshots/project-types.png) 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-projen", 3 | "description": "Projen helpers and utilities", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/MarkMcCulloh/vscode-projen.git" 7 | }, 8 | "scripts": { 9 | "build": "npx projen build", 10 | "bump": "npx projen bump", 11 | "clobber": "npx projen clobber", 12 | "compile": "npx projen compile", 13 | "default": "npx projen default", 14 | "eject": "npx projen eject", 15 | "eslint": "npx projen eslint", 16 | "package": "npx projen package", 17 | "post-compile": "npx projen post-compile", 18 | "post-upgrade": "npx projen post-upgrade", 19 | "pre-compile": "npx projen pre-compile", 20 | "release": "npx projen release", 21 | "test": "npx projen test", 22 | "test:watch": "npx projen test:watch", 23 | "unbump": "npx projen unbump", 24 | "upgrade": "npx projen upgrade", 25 | "watch": "npx projen watch", 26 | "projen": "npx projen" 27 | }, 28 | "devDependencies": { 29 | "@types/gunzip-maybe": "^1.4.2", 30 | "@types/jest": "^27.5.2", 31 | "@types/node": "^20", 32 | "@types/pacote": "^11.1.8", 33 | "@types/tar-stream": "^3.1.3", 34 | "@typescript-eslint/eslint-plugin": "^6", 35 | "@typescript-eslint/parser": "^6", 36 | "@vscode/vsce": "^2.26.1", 37 | "constructs": "^10.0.0", 38 | "esbuild": "^0.21.3", 39 | "eslint": "^8", 40 | "eslint-config-prettier": "^8.10.0", 41 | "eslint-import-resolver-typescript": "^2.7.1", 42 | "eslint-plugin-import": "^2.29.1", 43 | "eslint-plugin-prettier": "^4.2.1", 44 | "jest": "^29.7.0", 45 | "jest-junit": "^15", 46 | "prettier": "^2.8.8", 47 | "projen": "^0.81.15", 48 | "shx": "^0.3.4", 49 | "ts-jest": "^29.1.3", 50 | "ts-node": "^9", 51 | "typescript": "^5.4.5" 52 | }, 53 | "dependencies": { 54 | "@types/vscode": "^1.89.0", 55 | "gunzip-maybe": "^1.4.2", 56 | "pacote": "^18.0.6", 57 | "registry-url": "^6.0.1", 58 | "tar-stream": "^3.1.7" 59 | }, 60 | "engines": { 61 | "node": ">= 20.0.0", 62 | "vscode": "^1.62.0" 63 | }, 64 | "main": "./lib/extension.js", 65 | "license": "Apache-2.0", 66 | "version": "0.0.0", 67 | "jest": { 68 | "testMatch": [ 69 | "/src/**/__tests__/**/*.ts?(x)", 70 | "/@(test|src)/**/*(*.)@(spec|test).ts?(x)" 71 | ], 72 | "clearMocks": true, 73 | "collectCoverage": true, 74 | "coverageReporters": [ 75 | "json", 76 | "lcov", 77 | "clover", 78 | "cobertura", 79 | "text" 80 | ], 81 | "coverageDirectory": "coverage", 82 | "coveragePathIgnorePatterns": [ 83 | "/node_modules/" 84 | ], 85 | "testPathIgnorePatterns": [ 86 | "/node_modules/" 87 | ], 88 | "watchPathIgnorePatterns": [ 89 | "/node_modules/" 90 | ], 91 | "reporters": [ 92 | "default", 93 | [ 94 | "jest-junit", 95 | { 96 | "outputDirectory": "test-reports" 97 | } 98 | ] 99 | ], 100 | "transform": { 101 | "^.+\\.[t]sx?$": [ 102 | "ts-jest", 103 | { 104 | "tsconfig": "tsconfig.dev.json" 105 | } 106 | ] 107 | } 108 | }, 109 | "types": "lib/extension.d.ts", 110 | "displayName": "Projen", 111 | "icon": "resources/projen.png", 112 | "preview": false, 113 | "publisher": "MarkMcCulloh", 114 | "activationEvents": [ 115 | "workspaceContains:.projen/**", 116 | "onView:projen", 117 | "onStartupFinished" 118 | ], 119 | "contributes": { 120 | "configuration": { 121 | "title": "Projen", 122 | "properties": { 123 | "projen.projects.externalLibraries": { 124 | "type": "string", 125 | "editPresentation": "multilineText", 126 | "default": "", 127 | "description": "When creating a new project, these external libraries will show as options.\nSeparate with newlines.\nMay use `|` after library name to add documentation (e.g. `vue-projen | Vue templates`)." 128 | }, 129 | "projen.tasks.executeInTerminal": { 130 | "type": "boolean", 131 | "default": false, 132 | "description": "When running a task, use the integrated terminal instead of the special task window." 133 | }, 134 | "projen.terminal.alwaysChangeToWorkspaceDirectory": { 135 | "type": "boolean", 136 | "default": true, 137 | "description": "Before running each command in the integrated terminal, always change the directory to the root." 138 | }, 139 | "projen.managedFiles.decoration.enable": { 140 | "type": "boolean", 141 | "default": true, 142 | "description": "Label and darken projen-managed files in the explorer." 143 | }, 144 | "projen.managedFiles.decoration.badge": { 145 | "type": "string", 146 | "default": "PJ", 147 | "description": "MUST BE < 3 CHARACTERS.\nText of the label applied to managed projen files. Can leave empty to remove." 148 | }, 149 | "projen.managedFiles.decoration.themeColor": { 150 | "type": "string", 151 | "default": "gitDecoration.ignoredResourceForeground", 152 | "description": "ThemeColor id to apply to managed files. Leave empty to not apply any color." 153 | } 154 | } 155 | }, 156 | "taskDefinitions": [ 157 | { 158 | "type": "projen", 159 | "required": [ 160 | "task" 161 | ], 162 | "when": "shellExecutionSupported && projen.inProject", 163 | "properties": { 164 | "task": { 165 | "type": "string", 166 | "description": "The projen task to execute" 167 | } 168 | } 169 | } 170 | ], 171 | "viewsContainers": { 172 | "activitybar": [ 173 | { 174 | "id": "projen", 175 | "title": "Projen", 176 | "icon": "resources/dark/projen-outline.svg" 177 | } 178 | ] 179 | }, 180 | "views": { 181 | "projen": [ 182 | { 183 | "id": "projenProjects", 184 | "name": "Projects" 185 | } 186 | ] 187 | }, 188 | "commands": [ 189 | { 190 | "command": "projen.run", 191 | "title": "Run Projen", 192 | "icon": { 193 | "light": "resources/light/projen-outline.svg", 194 | "dark": "resources/dark/projen-outline.svg" 195 | } 196 | }, 197 | { 198 | "command": "projen.runTask", 199 | "title": "Run Projen Task", 200 | "icon": "$(play)" 201 | }, 202 | { 203 | "command": "projen.openProjenRc", 204 | "title": "Open Projen File", 205 | "icon": "$(gear)" 206 | }, 207 | { 208 | "command": "projen.new", 209 | "title": "Generate Projen Project" 210 | } 211 | ], 212 | "menus": { 213 | "view/title": [ 214 | { 215 | "command": "projen.run", 216 | "group": "navigation", 217 | "when": "projen.inProject == true && view == projenProjects" 218 | }, 219 | { 220 | "command": "projen.openProjenRc", 221 | "group": "navigation", 222 | "when": "projen.inProject == true && view == projenProjects" 223 | }, 224 | { 225 | "command": "projen.run", 226 | "group": "navigation", 227 | "when": "projen.inProject == true && activeViewlet == 'workbench.view.explorer'" 228 | }, 229 | { 230 | "command": "projen.openProjenRc", 231 | "group": "navigation", 232 | "when": "projen.inProject == true && activeViewlet == 'workbench.view.explorer'" 233 | } 234 | ] 235 | } 236 | }, 237 | "browser": "./lib/extension.js", 238 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 239 | } 240 | -------------------------------------------------------------------------------- /resources/dark/projen-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | pj 120 | pj 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /resources/light/projen-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | pj 120 | pj 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /resources/projen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMcCulloh/vscode-projen/9e96fa2d4cdc2557ad52d8fa02680ccb8d077b66/resources/projen.png -------------------------------------------------------------------------------- /resources/projen.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | 32 | 34 | 36 | 38 | 41 | 44 | 47 | 50 | 54 | 55 | 59 | 62 | 66 | 67 | 68 | 69 | 71 | 73 | 78 | 82 | 86 | 87 | 88 | 89 | 92 | 95 | 98 | 102 | 103 | 107 | 110 | 114 | 115 | 116 | 117 | 118 | 121 | 126 | 130 | 134 | 135 | 138 | 141 | 144 | 147 | 151 | 152 | 156 | 159 | 163 | 164 | 165 | 166 | 168 | 170 | 175 | 179 | 183 | 184 | 185 | 186 | 189 | 193 | 196 | pj 206 | 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /screenshots/files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMcCulloh/vscode-projen/9e96fa2d4cdc2557ad52d8fa02680ccb8d077b66/screenshots/files.png -------------------------------------------------------------------------------- /screenshots/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMcCulloh/vscode-projen/9e96fa2d4cdc2557ad52d8fa02680ccb8d077b66/screenshots/overview.png -------------------------------------------------------------------------------- /screenshots/project-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMcCulloh/vscode-projen/9e96fa2d4cdc2557ad52d8fa02680ccb8d077b66/screenshots/project-types.png -------------------------------------------------------------------------------- /screenshots/tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMcCulloh/vscode-projen/9e96fa2d4cdc2557ad52d8fa02680ccb8d077b66/screenshots/tasks.png -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as vscode from "vscode"; 4 | import { getProjectIds } from "./jsii/fetcher"; 5 | import { ProjenInfo } from "./projen_info"; 6 | import { ProjenView } from "./projen_view"; 7 | import { ProjenWatcher } from "./projen_watcher"; 8 | 9 | function useTerminal() { 10 | return vscode.workspace 11 | .getConfiguration("projen") 12 | .get("tasks.executeInTerminal"); 13 | } 14 | 15 | function availableProjectLibraries() { 16 | const fromConfig = 17 | vscode.workspace 18 | .getConfiguration("projen") 19 | .get("projects.externalLibraries") ?? ""; 20 | 21 | const externalOptions = `${fromConfig}\n[External Library...]`.trim(); 22 | 23 | return [ 24 | "Projen", 25 | ...externalOptions.split("\n"), 26 | // None of these seem to work with the current projen version :( 27 | // "@cdktf/provider-project | To create prebuilt provider packages for Terraform CDK", 28 | // "cdk-appsync-project | AWS AppSync API project that uses the cdk-appsync-transformer", 29 | // "@svelte-up/projen-rust-project | Cargo-based rustlang projects", 30 | // "p6-projen-project-awesome-list | Setup an Awesome List repository", 31 | // "yarn-projen | Manage monorepos using Yarn workspaces", 32 | // "lerna-projen | Manage monorepos using Lern", 33 | ]; 34 | } 35 | 36 | // this method is called when your extension is activated 37 | // your extension is activated the very first time the command is executed 38 | export async function activate(context: vscode.ExtensionContext) { 39 | if (!vscode.workspace.workspaceFolders?.[0]) { 40 | return; 41 | } 42 | 43 | let projects: ProjenInfo[] = []; 44 | for (const folder of vscode.workspace.workspaceFolders) { 45 | const folderProjects = await findProjectInFolder(folder); 46 | const filteredProjects = folderProjects 47 | .filter((f) => { 48 | if (projects.some((p) => p.projectRoot.path === f.path)) { 49 | return false; 50 | } else { 51 | return true; 52 | } 53 | }) 54 | .map((p) => new ProjenInfo(folder, p)); 55 | 56 | projects.push(...filteredProjects); 57 | } 58 | projects.sort((a, b) => a.label.localeCompare(b.label)); 59 | 60 | const singleProject = projects.length === 1; 61 | 62 | async function quickPickProject() { 63 | if (singleProject) { 64 | return projects[0]; 65 | } 66 | const selection = await vscode.window.showQuickPick( 67 | projects.map((t) => t.label), 68 | { placeHolder: "Select projent project" } 69 | ); 70 | 71 | return projects.find((p) => p.label === selection)!; 72 | } 73 | 74 | function newOrActiveTerminal(projenInfo: ProjenInfo) { 75 | const terminalName = singleProject 76 | ? `[projen]` 77 | : `[projen][${projenInfo.label}]`; 78 | 79 | let terminal = vscode.window.terminals.find((t) => t.name === terminalName); 80 | if (!terminal) { 81 | terminal = vscode.window.createTerminal(terminalName); 82 | } else if ( 83 | vscode.workspace 84 | .getConfiguration("projen") 85 | .get("terminal.alwaysChangeToWorkspaceDirectory") 86 | ) { 87 | terminal.sendText(getCDCommand(projenInfo.projectRoot)); 88 | } 89 | 90 | terminal.show(); 91 | return terminal; 92 | } 93 | 94 | function getVSCodeTask( 95 | projenInfo: ProjenInfo, 96 | name: string, 97 | ...args: string[] 98 | ) { 99 | args.unshift("projen"); 100 | 101 | const taskName = singleProject ? name : `${name} [${projenInfo.label}]`; 102 | 103 | return new vscode.Task( 104 | { type: "projen", task: taskName }, 105 | vscode.TaskScope.Workspace, 106 | taskName, 107 | "projen", 108 | new vscode.ProcessExecution("npx", args, { 109 | cwd: projenInfo.projectRoot.fsPath, 110 | }), 111 | // TODO: Use dynamic problem matchers 112 | ["$tsc", "$eslint-compact"] 113 | ); 114 | } 115 | 116 | context.subscriptions.push( 117 | vscode.commands.registerCommand("projen.openProjenRc", async () => { 118 | const projenInfo = await quickPickProject(); 119 | 120 | const files = await vscode.workspace.findFiles( 121 | new vscode.RelativePattern(projenInfo.projectRoot, ".projenrc.{ts,js}") 122 | ); 123 | 124 | if (files.length > 0) { 125 | const doc = await vscode.workspace.openTextDocument(files[0]); 126 | await vscode.window.showTextDocument(doc); 127 | } 128 | }) 129 | ); 130 | 131 | context.subscriptions.push( 132 | vscode.commands.registerCommand("projen.run", async () => { 133 | const projenInfo = await quickPickProject(); 134 | if (useTerminal()) { 135 | newOrActiveTerminal(projenInfo).sendText(`npx projen`); 136 | } else { 137 | void vscode.tasks.executeTask(getVSCodeTask(projenInfo, "projen")); 138 | } 139 | }) 140 | ); 141 | 142 | context.subscriptions.push( 143 | vscode.commands.registerCommand( 144 | "projen.new", 145 | async (projectLib?: string, projectType?: string) => { 146 | const rawProjectLibSelection: string | undefined = 147 | projectLib ?? 148 | (await vscode.window.showQuickPick(availableProjectLibraries(), { 149 | title: "Project Library", 150 | placeHolder: "Select library to view available projects", 151 | })); 152 | 153 | if (!rawProjectLibSelection) { 154 | return; 155 | } 156 | 157 | let projectLibSelection = rawProjectLibSelection 158 | .toLowerCase() 159 | .split("|")[0] 160 | .trim(); 161 | 162 | if (projectLibSelection === "[external library...]") { 163 | const customLib = await vscode.window.showInputBox({ 164 | prompt: "Specify external library", 165 | title: "External Library Selection", 166 | }); 167 | 168 | if (!customLib) { 169 | return; 170 | } 171 | 172 | projectLibSelection = customLib.toLowerCase().trim(); 173 | } 174 | 175 | let projectTypes = projectType 176 | ? [] 177 | : await getProjectIds(projectLibSelection); 178 | 179 | let projectId: string | undefined = projectType; 180 | 181 | if (projectTypes.length > 1) { 182 | // If there are multiple projectTypes, we need a pjid 183 | projectTypes = projectTypes.filter((p) => !!p.pjid); 184 | } 185 | 186 | if (projectTypes.length === 0 && !projectType) { 187 | void vscode.window.showErrorMessage( 188 | `Unable to find available project types from "${projectLibSelection}"` 189 | ); 190 | return; 191 | } 192 | 193 | if (projectTypes.length > 0) { 194 | const projectPickerPromise = new Promise( 195 | (resolve) => { 196 | const picker = vscode.window.createQuickPick(); 197 | picker.canSelectMany = false; 198 | picker.title = "Project Type Selection"; 199 | picker.placeholder = "Select project type"; 200 | picker.matchOnDetail = true; 201 | picker.items = projectTypes.map((project) => ({ 202 | detail: project.pjid ?? "", 203 | label: project.summary ?? project.typeName, 204 | })); 205 | 206 | picker.onDidAccept(() => { 207 | if (picker.selectedItems && picker.selectedItems.length > 0) { 208 | resolve(picker.selectedItems[0].detail); 209 | picker.hide(); 210 | } 211 | }); 212 | picker.onDidHide(() => { 213 | resolve(undefined); 214 | picker.dispose(); 215 | }); 216 | 217 | picker.show(); 218 | } 219 | ); 220 | 221 | projectId = await projectPickerPromise; 222 | } 223 | 224 | if (projectId === undefined) { 225 | return; 226 | } 227 | 228 | const additionalArgs = await vscode.window.showInputBox({ 229 | prompt: "(Optional) Additional arguments to pass to 'projen new'", 230 | }); 231 | 232 | if (additionalArgs === undefined) { 233 | return; 234 | } 235 | 236 | let args = ""; 237 | if (projectLibSelection !== "projen") { 238 | args += ` --from ${projectLibSelection}`; 239 | } 240 | if (projectId) { 241 | args += " " + projectId; 242 | } 243 | if (additionalArgs) { 244 | args += " " + additionalArgs; 245 | } 246 | args = args.trim(); 247 | 248 | const terminal = vscode.window.createTerminal("[projen]"); 249 | terminal.sendText(`npx projen new ${args}`); 250 | } 251 | ) 252 | ); 253 | 254 | const overview = new ProjenView(projects); 255 | vscode.window.createTreeView("projenProjects", { 256 | treeDataProvider: overview, 257 | showCollapseAll: true, 258 | }); 259 | 260 | vscode.tasks.registerTaskProvider("projen", { 261 | provideTasks(_token?: vscode.CancellationToken) { 262 | return projects.flatMap((p) => { 263 | return p.tasks.map((t) => getVSCodeTask(p, t.name, t.name)); 264 | }); 265 | }, 266 | resolveTask(task: vscode.Task, _token?: vscode.CancellationToken) { 267 | return task; 268 | }, 269 | }); 270 | 271 | context.subscriptions.push( 272 | vscode.commands.registerCommand( 273 | "projen.runTask", 274 | async (projenInfo?: ProjenInfo, task?: string) => { 275 | if (!projenInfo) { 276 | projenInfo = await quickPickProject(); 277 | } 278 | 279 | if (task) { 280 | if (useTerminal()) { 281 | newOrActiveTerminal(projenInfo).sendText(`npx projen ${task}`); 282 | } else { 283 | void vscode.tasks.executeTask( 284 | getVSCodeTask(projenInfo, task, task) 285 | ); 286 | } 287 | } else { 288 | const selection = await vscode.window.showQuickPick( 289 | projenInfo.tasks.map((t) => t.name) 290 | ); 291 | 292 | if (selection) { 293 | if (useTerminal()) { 294 | newOrActiveTerminal(projenInfo).sendText( 295 | `npx projen ${selection}` 296 | ); 297 | } else { 298 | void vscode.tasks.executeTask( 299 | getVSCodeTask(projenInfo, selection, selection) 300 | ); 301 | } 302 | } 303 | } 304 | } 305 | ) 306 | ); 307 | 308 | const updateStuff = (projenInfo: ProjenInfo) => { 309 | void projenInfo.update().then(() => { 310 | overview._onDidChangeTreeData.fire(); 311 | }); 312 | }; 313 | 314 | const projenWatchers = projects.map((p) => new ProjenWatcher(p)); 315 | projenWatchers.forEach((w) => 316 | w.onDirectoryChange(() => updateStuff(w.projenInfo)) 317 | ); 318 | 319 | for (const p of projects) { 320 | await p.update(); 321 | } 322 | 323 | overview._onDidChangeTreeData.fire(); 324 | } 325 | 326 | // this method is called when your extension is deactivated 327 | export function deactivate() {} 328 | 329 | function getCDCommand(cwd: vscode.Uri): string { 330 | if (process && global.process.platform === "win32") { 331 | if (vscode.env.shell !== "cmd.exe") { 332 | return `cd "${cwd.fsPath.replace(/\\/g, "/")}"`; 333 | } 334 | } 335 | 336 | return `cd "${cwd}"`; 337 | } 338 | 339 | async function findProjectInFolder(workspaceFolder?: vscode.WorkspaceFolder) { 340 | if (!workspaceFolder) { 341 | return []; 342 | } 343 | const exclusions: string[] = ["**/node_modules", "**/cdk.out", "**/dist"]; 344 | const pattern: string = "**/.projen/tasks.json"; 345 | const depFileList = await vscode.workspace.findFiles( 346 | new vscode.RelativePattern(workspaceFolder, pattern), 347 | `{${exclusions.join(",")}}` 348 | ); 349 | 350 | const cleanupList = depFileList.map((f) => { 351 | return f.with({ path: f.path.replace("/.projen/tasks.json", "") }); 352 | }); 353 | 354 | return cleanupList; 355 | } 356 | -------------------------------------------------------------------------------- /src/generated_file_decorator.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export class GeneratedFileDecorationProvider 4 | implements vscode.FileDecorationProvider 5 | { 6 | private static Decoration: vscode.FileDecoration = { 7 | color: new vscode.ThemeColor( 8 | vscode.workspace 9 | .getConfiguration("projen") 10 | .get("managedFiles.decoration.themeColor")! 11 | ), 12 | badge: vscode.workspace 13 | .getConfiguration("projen") 14 | .get("managedFiles.decoration.badge"), 15 | tooltip: "Managed By Projen. Edit the projenrc file to make changes.", 16 | }; 17 | private lastBadge: string = "PJ"; 18 | private lastColor: string = "gitDecoration.ignoredResourceForeground"; 19 | 20 | public files: string[]; 21 | 22 | public _onDidChangeFileDecorations: vscode.EventEmitter = 23 | new vscode.EventEmitter(); 24 | readonly onDidChangeFileDecorations: vscode.Event = 25 | this._onDidChangeFileDecorations.event; 26 | 27 | constructor() { 28 | this.files = []; 29 | } 30 | 31 | provideFileDecoration( 32 | uri: vscode.Uri, 33 | _token: vscode.CancellationToken 34 | ): vscode.ProviderResult { 35 | if ( 36 | this.files.length == 0 || 37 | !vscode.workspace 38 | .getConfiguration("projen") 39 | .get("managedFiles.decoration.enable") 40 | ) { 41 | return null; 42 | } 43 | 44 | if (this.files.includes(uri.toString())) { 45 | const newBadge = vscode.workspace 46 | .getConfiguration("projen") 47 | .get("managedFiles.decoration.badge") as string; 48 | if (this.lastBadge !== newBadge) { 49 | GeneratedFileDecorationProvider.Decoration.badge = newBadge; 50 | } 51 | const newColor = vscode.workspace 52 | .getConfiguration("projen") 53 | .get("managedFiles.decoration.themeColor") as string; 54 | if (this.lastColor !== newColor) { 55 | GeneratedFileDecorationProvider.Decoration.color = 56 | new vscode.ThemeColor(newColor); 57 | } 58 | 59 | return GeneratedFileDecorationProvider.Decoration; 60 | } else { 61 | return null; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/jsii/fetcher.ts: -------------------------------------------------------------------------------- 1 | import { Readable } from "stream"; 2 | import gunzip from "gunzip-maybe"; 3 | import { tarball } from "pacote"; 4 | import { extract } from "tar-stream"; 5 | 6 | async function getRegistryUrl(scope: string | undefined) { 7 | const registryUrl = await import("registry-url"); 8 | const url = registryUrl.default(scope); 9 | return url; 10 | } 11 | export interface RemoteProjenProjectInfo { 12 | typeName: string; 13 | pjid?: string; 14 | summary?: string; 15 | } 16 | 17 | // This function is partially taken projen, but made a bit worse to speed it up 18 | function isProjectType(jsiiTypes: any, fqn: string) { 19 | const type = jsiiTypes[fqn]; 20 | 21 | if (!type) { 22 | throw new Error( 23 | `Could not find project type with fqn "${fqn}" in .jsii file.` 24 | ); 25 | } 26 | 27 | if (type.kind !== "class") { 28 | return false; 29 | } 30 | if (type.abstract) { 31 | return false; 32 | } 33 | 34 | if (type.docs?.deprecated) { 35 | return false; 36 | } 37 | 38 | if (type.docs?.custom?.pjid) { 39 | return true; 40 | } 41 | 42 | let curr = type; 43 | while (true) { 44 | const lastBase = curr.base; 45 | 46 | if (curr.fqn === "projen.Project") { 47 | return true; 48 | } 49 | 50 | if (!lastBase) { 51 | return curr.fqn.startsWith("projen.") && curr.fqn.endsWith("Project"); 52 | } 53 | 54 | curr = jsiiTypes[lastBase]; 55 | if (!curr) { 56 | return lastBase.startsWith("projen.") && lastBase.endsWith("Project"); 57 | } 58 | } 59 | } 60 | 61 | // TODO 62 | // Probably need better handling of the streams, but honestly I'm not sure 63 | export async function getProjectIds( 64 | spec: string 65 | ): Promise { 66 | const jsiiManifest = await getJSII(spec); 67 | if (jsiiManifest && jsiiManifest.types) { 68 | return Object.keys(jsiiManifest.types) 69 | .filter((fqn: string) => isProjectType(jsiiManifest.types, fqn)) 70 | .map((fqn: string) => { 71 | const t = jsiiManifest.types[fqn]; 72 | return { 73 | pjid: t.docs?.custom?.pjid, 74 | summary: t.docs?.summary, 75 | typeName: t.name, 76 | }; 77 | }); 78 | } 79 | 80 | return []; 81 | } 82 | 83 | export async function getJSII(spec: string): Promise { 84 | return new Promise(async (resolve, _reject) => { 85 | let scope; 86 | if (spec.startsWith("@")) { 87 | scope = spec.split("/")[0]; 88 | } 89 | 90 | const tarballData = await tarball(spec, { 91 | registry: await getRegistryUrl(scope), 92 | }); 93 | 94 | const tarballStream = new Readable(); 95 | tarballStream._read = () => {}; // _read is required but you can noop it 96 | tarballStream.push(tarballData); 97 | tarballStream.push(null); 98 | 99 | var extractPipe = extract(); 100 | 101 | let allChunks = ""; 102 | const returnChunks = () => { 103 | if (allChunks) { 104 | resolve(JSON.parse(allChunks)); 105 | } else { 106 | resolve(null); 107 | } 108 | }; 109 | 110 | extractPipe 111 | .on("entry", function (header, stream, next) { 112 | if (header.name == "package/.jsii") { 113 | stream.on("data", function (chunk) { 114 | allChunks += chunk.toString(); 115 | }); 116 | stream.on("end", function () { 117 | extractPipe.destroy(); 118 | tarballStream.destroy(); 119 | }); 120 | } else { 121 | stream.on("end", function () { 122 | next(); 123 | }); 124 | } 125 | 126 | stream.resume(); 127 | }) 128 | .on("end", returnChunks) 129 | .on("close", returnChunks); 130 | 131 | tarballStream.pipe(gunzip()).pipe(extractPipe).on("close", returnChunks); 132 | }); 133 | } 134 | -------------------------------------------------------------------------------- /src/project/project_type.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { IgnoreFile } from "projen"; 3 | import { JobPermission, JobStep } from "projen/lib/github/workflows-model"; 4 | import { Release } from "projen/lib/release"; 5 | import { 6 | TypeScriptAppProject, 7 | TypeScriptProjectOptions, 8 | } from "projen/lib/typescript"; 9 | import { 10 | VSCodeExtensionCapabilities, 11 | VSCodeExtensionContributions, 12 | } from "./vscode_types"; 13 | 14 | export interface VSCodeExtensionProjectOptions 15 | extends TypeScriptProjectOptions { 16 | readonly publishToVSMarketplace?: boolean; 17 | readonly publishToOpenVSXRegistry?: boolean; 18 | readonly vsMarketplaceToken?: string; 19 | readonly vsxRegistryToken?: string; 20 | readonly vscodeVersion: string; 21 | readonly displayName: string; 22 | readonly publisher: string; 23 | readonly preview: boolean; 24 | readonly icon: string; 25 | readonly activationEvents: string[]; 26 | readonly categories?: string[]; 27 | readonly capabilities?: VSCodeExtensionCapabilities; 28 | readonly contributes: VSCodeExtensionContributions; 29 | readonly keywords?: string[]; 30 | } 31 | 32 | export class VSCodeExtensionProject extends TypeScriptAppProject { 33 | public readonly release?: Release; 34 | public readonly vscodeIgnore?: IgnoreFile; 35 | 36 | constructor(options: VSCodeExtensionProjectOptions) { 37 | super(options); 38 | 39 | const esbuildBase = 40 | "esbuild ./src/extension.ts --outfile=lib/extension.js --external:node-gyp --external:vscode --format=cjs --platform=node --bundle"; 41 | 42 | this.addDeps("@types/vscode"); 43 | this.addDevDeps("@vscode/vsce", "esbuild"); 44 | 45 | this.vscodeIgnore = new IgnoreFile(this, ".vscodeignore"); 46 | this.vscodeIgnore.addPatterns( 47 | ".vscode/**", 48 | ".vscode-test/**", 49 | "src/**", 50 | ".gitignore", 51 | "**/tsconfig.json", 52 | "**/.eslintrc.json", 53 | "**/*.map", 54 | "**/*.ts", 55 | "node_modules/", 56 | "dist/", 57 | "test/", 58 | "test-reports/", 59 | "coverage/", 60 | ".projen/" 61 | ); 62 | this.gitignore.addPatterns("out", "*.vsix", ".vscode-test"); 63 | 64 | this.package.addEngine("vscode", options.vscodeVersion); 65 | this.package.addField("displayName", options.displayName); 66 | this.package.addField("icon", options.icon); 67 | this.package.addField("preview", options.preview); 68 | this.package.addField("publisher", options.publisher); 69 | 70 | if (options.categories) { 71 | this.package.addField("categories", options.categories); 72 | } 73 | 74 | this.package.addField("activationEvents", options.activationEvents); 75 | this.package.addField("contributes", options.contributes); 76 | 77 | if (options.publishToVSMarketplace || options.publishToOpenVSXRegistry) { 78 | if (!this.release) { 79 | this.release = new Release(this, { 80 | artifactsDirectory: "dist", 81 | branch: options.defaultReleaseBranch, 82 | task: this.buildTask, 83 | versionFile: "package.json", 84 | releaseWorkflowName: "Publish", 85 | }); 86 | } 87 | 88 | const steps: JobStep[] = [ 89 | { 90 | name: "Download build artifacts", 91 | uses: "actions/download-artifact@v4", 92 | with: { 93 | name: "build-artifact", 94 | path: "dist", 95 | }, 96 | }, 97 | ]; 98 | 99 | if (options.publishToOpenVSXRegistry) { 100 | steps.push({ 101 | name: "Publish to Open VSX Registry", 102 | uses: "HaaLeo/publish-vscode-extension@v1", 103 | with: { 104 | pat: `\${{ secrets.${ 105 | options.vsxRegistryToken ?? "VSX_REGISTRY_TOKEN" 106 | } }}`, 107 | extensionFile: "./dist/extension.vsix", 108 | }, 109 | }); 110 | } 111 | 112 | if (options.publishToVSMarketplace) { 113 | steps.push({ 114 | name: "Publish to VS Marketplace", 115 | uses: "HaaLeo/publish-vscode-extension@v1", 116 | with: { 117 | pat: `\${{ secrets.${ 118 | options.vsMarketplaceToken ?? "VS_MARKETPLACE_TOKEN" 119 | } }}`, 120 | registryUrl: "https://marketplace.visualstudio.com", 121 | extensionFile: "./dist/extension.vsix", 122 | }, 123 | }); 124 | } 125 | 126 | this.release.addJobs({ 127 | release_marketplace: { 128 | name: "Publish Extension", 129 | runsOn: ["ubuntu-latest"], 130 | needs: ["release_github"], 131 | permissions: { contents: JobPermission.READ }, 132 | steps, 133 | }, 134 | }); 135 | 136 | this.compileTask.reset("tsc --noEmit"); 137 | this.compileTask.exec(esbuildBase); 138 | 139 | const packageTask = this.tasks.tryFind("package")!; 140 | packageTask.exec("mkdir -p dist"); 141 | packageTask.exec(`${esbuildBase} --minify`); 142 | packageTask.exec("vsce package -o dist/extension.vsix"); 143 | 144 | this.tasks.tryFind("release")?.prependExec("npm ci"); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/project/vscode_types.ts: -------------------------------------------------------------------------------- 1 | // from https://github.com/microsoft/vscode/blob/main/src/vs/platform/extensions/common/extensions.ts 2 | 3 | export interface VSCodeExtensionContributions { 4 | readonly commands?: VSCodeCommand[]; 5 | readonly configuration?: VSCodeConfiguration | VSCodeConfiguration[]; 6 | readonly debuggers?: VSCodeDebugger[]; 7 | readonly grammars?: VSCodeGrammar[]; 8 | readonly jsonValidation?: VSCodeJSONValidation[]; 9 | readonly keybindings?: VSCodeKeyBinding[]; 10 | readonly languages?: VSCodeLanguage[]; 11 | readonly menus?: { [context: string]: VSCodeMenu[] }; 12 | readonly snippets?: VSCodeSnippet[]; 13 | readonly themes?: VSCodeTheme[]; 14 | readonly iconThemes?: VSCodeTheme[]; 15 | readonly productIconThemes?: VSCodeTheme[]; 16 | readonly viewsContainers?: { [location: string]: VSCodeViewContainer[] }; 17 | readonly views?: { [location: string]: VSCodeView[] }; 18 | readonly colors?: VSCodeColor[]; 19 | readonly taskDefinitions?: VSCodeTaskDefinitions[]; 20 | // localizations?: VSCodeLocalization[]; 21 | readonly customEditors?: readonly VSCodeWebviewEditor[]; 22 | readonly codeActions?: readonly VSCodeCodeActionContribution[]; 23 | readonly authentication?: VSCodeAuthenticationContribution[]; 24 | readonly walkthroughs?: VSCodeWalkthrough[]; 25 | readonly startEntries?: VSCodeStartEntry[]; 26 | readonly notebooks?: VSCodeNotebookEntry[]; 27 | readonly notebookRenderer?: VSCodeNotebookRendererContribution[]; 28 | } 29 | 30 | export interface VSCodeTaskDefinitions { 31 | type?: string; 32 | required?: string[]; 33 | properties?: any; 34 | when?: string; 35 | } 36 | 37 | export interface VSCodeConfigurationProperty { 38 | readonly description: string; 39 | readonly type: string | string[]; 40 | readonly default?: any; 41 | readonly editPresentation?: string; 42 | } 43 | 44 | export interface VSCodeConfiguration { 45 | readonly id?: string; 46 | readonly order?: number; 47 | readonly title?: string; 48 | readonly properties: { [key: string]: VSCodeConfigurationProperty }; 49 | } 50 | 51 | export interface VSCodeDebugger { 52 | readonly label?: string; 53 | readonly type: string; 54 | readonly runtime?: string; 55 | } 56 | 57 | export interface VSCodeGrammar { 58 | readonly language: string; 59 | } 60 | 61 | export interface VSCodeJSONValidation { 62 | readonly fileMatch: string | string[]; 63 | readonly url: string; 64 | } 65 | 66 | export interface VSCodeKeyBinding { 67 | readonly command: string; 68 | readonly key: string; 69 | readonly when?: string; 70 | readonly mac?: string; 71 | readonly linux?: string; 72 | readonly win?: string; 73 | } 74 | 75 | export interface VSCodeLanguage { 76 | readonly id: string; 77 | readonly extensions: string[]; 78 | readonly aliases: string[]; 79 | } 80 | 81 | export interface VSCodeMenu { 82 | readonly command: string; 83 | readonly alt?: string; 84 | readonly when?: string; 85 | readonly group?: string; 86 | } 87 | 88 | export interface VSCodeSnippet { 89 | readonly language: string; 90 | } 91 | 92 | export interface VSCodeTheme { 93 | readonly label: string; 94 | } 95 | 96 | export interface VSCodeViewContainer { 97 | readonly id: string; 98 | readonly title: string; 99 | readonly icon?: string | { dark: string; light: string; hc?: string }; 100 | } 101 | 102 | export interface VSCodeView { 103 | readonly id: string; 104 | readonly name: string; 105 | } 106 | 107 | export interface VSCodeColor { 108 | readonly id: string; 109 | readonly description: string; 110 | readonly defaults: { light: string; dark: string; highContrast: string }; 111 | } 112 | 113 | export interface VSCodeWebviewEditor { 114 | readonly viewType: string; 115 | readonly priority: string; 116 | readonly selector: readonly { 117 | readonly filenamePattern?: string; 118 | }[]; 119 | } 120 | 121 | export interface VSCodeCodeActionContributionAction { 122 | readonly kind: string; 123 | readonly title: string; 124 | readonly description?: string; 125 | } 126 | 127 | export interface VSCodeCodeActionContribution { 128 | readonly languages: readonly string[]; 129 | readonly actions: readonly VSCodeCodeActionContributionAction[]; 130 | } 131 | 132 | export interface VSCodeAuthenticationContribution { 133 | readonly id: string; 134 | readonly label: string; 135 | } 136 | 137 | export interface VSCodeWalkthroughStep { 138 | readonly id: string; 139 | readonly title: string; 140 | readonly description: string | undefined; 141 | readonly media: 142 | | { 143 | image: string | { dark: string; light: string; hc: string }; 144 | altText: string; 145 | markdown?: never; 146 | svg?: never; 147 | } 148 | | { markdown: string; image?: never; svg?: never } 149 | | { svg: string; altText: string; markdown?: never; image?: never }; 150 | readonly completionEvents?: string[]; 151 | /** @deprecated use `completionEvents: 'onCommand:...'` */ 152 | readonly doneOn?: { command: string }; 153 | readonly when?: string; 154 | } 155 | 156 | export interface VSCodeWalkthrough { 157 | readonly id: string; 158 | readonly title: string; 159 | readonly description: string; 160 | readonly steps: VSCodeWalkthroughStep[]; 161 | readonly featuredFor: string[] | undefined; 162 | readonly when?: string; 163 | } 164 | 165 | export interface VSCodeStartEntry { 166 | readonly title: string; 167 | readonly description: string; 168 | readonly command: string; 169 | readonly when?: string; 170 | readonly category: "file" | "folder" | "notebook"; 171 | } 172 | 173 | export interface VSCodeNotebookEntry { 174 | readonly type: string; 175 | readonly displayName: string; 176 | } 177 | 178 | export interface VSCodeNotebookRendererContribution { 179 | readonly id: string; 180 | readonly displayName: string; 181 | readonly mimeTypes: string[]; 182 | } 183 | 184 | export interface VSCodeCommand { 185 | readonly command: string; 186 | readonly title: string; 187 | readonly category?: string; 188 | readonly icon?: string | { dark: string; light: string; hc?: string }; 189 | } 190 | 191 | export const ALL_EXTENSION_KINDS: readonly ExtensionKind[] = [ 192 | "ui", 193 | "workspace", 194 | "web", 195 | ]; 196 | export type ExtensionKind = "ui" | "workspace" | "web"; 197 | 198 | export interface VSCodeExtensionCapabilities { 199 | readonly virtualWorkspaces?: ExtensionVirtualWorkspaceSupport; 200 | readonly untrustedWorkspaces?: ExtensionUntrustedWorkspaceSupport; 201 | } 202 | export type ExtensionUntrustedWorkspaceSupport = 203 | | { supported: true } 204 | | { supported: false; description: string } 205 | | { 206 | supported: LimitedWorkspaceSupportType; 207 | description: string; 208 | restrictedConfigurations?: string[]; 209 | }; 210 | export type LimitedWorkspaceSupportType = "limited"; 211 | export type ExtensionUntrustedWorkspaceSupportType = 212 | | boolean 213 | | LimitedWorkspaceSupportType; 214 | export type ExtensionVirtualWorkspaceSupportType = 215 | | boolean 216 | | LimitedWorkspaceSupportType; 217 | export type ExtensionVirtualWorkspaceSupport = 218 | | boolean 219 | | { supported: true } 220 | | { supported: false | LimitedWorkspaceSupportType; description: string }; 221 | -------------------------------------------------------------------------------- /src/projen_info.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { GeneratedFileDecorationProvider } from "./generated_file_decorator"; 3 | 4 | async function readTextFromFile(uri: vscode.Uri) { 5 | const readData = await vscode.workspace.fs.readFile(uri); 6 | return new TextDecoder("utf-8").decode(readData); 7 | } 8 | 9 | export class ProjenInfo { 10 | public managedFiles: vscode.Uri[] = []; 11 | public tasks: ProjenTask[] = []; 12 | public dependencies: ProjenDependency[] = []; 13 | public rcFile?: vscode.Uri; 14 | public label: string; 15 | previouslyManaged: vscode.Uri[]; 16 | decorator: GeneratedFileDecorationProvider; 17 | 18 | constructor( 19 | public workspaceFolder: vscode.WorkspaceFolder, 20 | public projectRoot: vscode.Uri 21 | ) { 22 | this.previouslyManaged = []; 23 | this.label = projectRoot.path 24 | .toLowerCase() 25 | .replace(workspaceFolder.uri.path.toLowerCase(), ""); 26 | 27 | if (this.label.startsWith("/")) { 28 | this.label = this.label.slice(1); 29 | } 30 | if (this.label === "") { 31 | this.label = workspaceFolder.name; 32 | } 33 | this.decorator = new GeneratedFileDecorationProvider(); 34 | vscode.window.registerFileDecorationProvider(this.decorator); 35 | } 36 | 37 | async update() { 38 | const projenFolderFiles = await vscode.workspace.findFiles( 39 | new vscode.RelativePattern(this.projectRoot, ".projen/*") 40 | ); 41 | const rootFiles = await vscode.workspace.findFiles( 42 | new vscode.RelativePattern(this.projectRoot, "*") 43 | ); 44 | 45 | if (projenFolderFiles.length == 0) { 46 | void vscode.commands.executeCommand( 47 | "setContext", 48 | "projen.inProject", 49 | false 50 | ); 51 | 52 | this.managedFiles = []; 53 | this.dependencies = []; 54 | this.decorator.files = []; 55 | 56 | if ( 57 | rootFiles.length === 0 && 58 | ( 59 | await vscode.workspace.findFiles( 60 | new vscode.RelativePattern(this.projectRoot, "**"), 61 | undefined, 62 | 1 63 | ) 64 | ).length === 0 65 | ) { 66 | // in an empty workspace 67 | 68 | const choice = await vscode.window.showInformationMessage( 69 | "Looks like you're in an empty folder, would you like to generate a project with projen?", 70 | "Sure!", 71 | "No Thanks!" 72 | ); 73 | 74 | if (choice === "Sure!") { 75 | void vscode.commands.executeCommand("projen.new"); 76 | } 77 | } 78 | 79 | return; 80 | } 81 | 82 | this.rcFile = rootFiles.find((r) => r.path.includes(".projenrc.")); 83 | 84 | let files: vscode.Uri[] = []; 85 | let verifiedFiles = false; 86 | 87 | const fileManifestUri = projenFolderFiles.find((f) => 88 | f.path.endsWith("files.json") 89 | ); 90 | if (fileManifestUri) { 91 | try { 92 | const fileManifest = await readTextFromFile(fileManifestUri); 93 | const fileData: string[] = JSON.parse(fileManifest).files; 94 | files = fileData.map((f) => vscode.Uri.joinPath(this.projectRoot, f)); 95 | 96 | // handles special cases 97 | const specialFiles = rootFiles.filter( 98 | (f) => 99 | f.path.endsWith("package-lock.json") || 100 | f.path.endsWith(".lock") || 101 | f.path.endsWith("package.json") 102 | ); 103 | if (specialFiles.length > 0) { 104 | files.push(...specialFiles); 105 | } 106 | 107 | verifiedFiles = true; 108 | } catch (error) { 109 | console.error(error); 110 | } 111 | 112 | if (files.length === 0) { 113 | files.push(...rootFiles, ...projenFolderFiles); 114 | } 115 | } 116 | 117 | void vscode.commands.executeCommand("setContext", "projen.inProject", true); 118 | 119 | const projenManaged: vscode.Uri[] = []; 120 | for (const f of files) { 121 | if ( 122 | verifiedFiles || 123 | f.path.endsWith("package-lock.json") || 124 | f.path.endsWith(".lock") 125 | ) { 126 | // TODO handle lockfiles in a smarter way 127 | // Since dependencies are managed by projen, a lockfile is as well (kinda) 128 | // lock files are typically huge, would much rather not try to search them 129 | projenManaged.push(f); 130 | } else { 131 | const fileContent = await readTextFromFile(f); 132 | if ( 133 | fileContent.includes( 134 | `~~` + ` Generated by projen. To modify, edit .projenrc` 135 | ) 136 | ) { 137 | projenManaged.push(f); 138 | } 139 | } 140 | } 141 | 142 | const taskFile = projenFolderFiles.find((file) => 143 | file.path.endsWith("tasks.json") 144 | ); 145 | if (taskFile) { 146 | const fileContent = await readTextFromFile(taskFile); 147 | const taskData = JSON.parse(fileContent).tasks; 148 | 149 | this.tasks = Object.values(taskData).map( 150 | (t: any) => new ProjenTask(this, t) 151 | ); 152 | this.tasks.sort((a, b) => a.name.localeCompare(b.name)); 153 | } 154 | 155 | const depFile = projenFolderFiles.find((file) => 156 | file.path.endsWith("deps.json") 157 | ); 158 | if (depFile) { 159 | const fileContent = await readTextFromFile(depFile); 160 | const depData = JSON.parse(fileContent).dependencies; 161 | depData.sort((a: any, b: any) => a.name.localeCompare(b.name)); 162 | 163 | this.dependencies = depData.map( 164 | (d: any) => new ProjenDependency(this, d.name, d.type, d.version) 165 | ); 166 | } 167 | 168 | const directoryMap: any = {}; 169 | projenManaged.forEach((f) => { 170 | const directory = f.with({ 171 | path: f.path.replace(/\\/g, "/").split("/").slice(0, -1).join("/"), 172 | }); 173 | 174 | if (directoryMap[directory.toString()] !== undefined) { 175 | directoryMap[directory.toString()]++; 176 | } else { 177 | directoryMap[directory.toString()] = 1; 178 | } 179 | }); 180 | 181 | let managedDirectories: vscode.Uri[] = []; 182 | for (const d of Object.keys(directoryMap)) { 183 | const dirUri = vscode.Uri.parse(d); 184 | const filesFromDir = await vscode.workspace.findFiles( 185 | new vscode.RelativePattern(dirUri, "*") 186 | ); 187 | 188 | if (directoryMap[d] === filesFromDir.length) { 189 | managedDirectories.push(dirUri); 190 | } 191 | } 192 | 193 | if (managedDirectories.length > 0) { 194 | projenManaged.push(...managedDirectories); 195 | } 196 | 197 | projenManaged.sort((a, b) => a.toString().localeCompare(b.toString())); 198 | 199 | this.decorator.files = projenManaged.map((f) => f.toString()); 200 | this.managedFiles = projenManaged; 201 | 202 | this.decorator._onDidChangeFileDecorations.fire( 203 | this.previouslyManaged.concat(...projenManaged) 204 | ); 205 | 206 | this.previouslyManaged = projenManaged; 207 | } 208 | } 209 | export class ProjenStep { 210 | constructor(public type: string, public value: string) {} 211 | } 212 | 213 | export class ProjenTask { 214 | public name: string; 215 | public description?: string; 216 | public steps: ProjenStep[]; 217 | public readonly projenInfo: ProjenInfo; 218 | 219 | constructor(projenInfo: ProjenInfo, taskData: any) { 220 | this.name = taskData.name; 221 | this.projenInfo = projenInfo; 222 | this.description = taskData.description; 223 | this.steps = (taskData.steps ?? []).map((s: any) => { 224 | const entries = Object.entries(s)[0]; 225 | return new ProjenStep(entries[0], entries[1] as any); 226 | }); 227 | } 228 | } 229 | 230 | export class ProjenDependency { 231 | constructor( 232 | public projenInfo: ProjenInfo, 233 | public name: string, 234 | public type: string, 235 | public version?: string 236 | ) {} 237 | } 238 | -------------------------------------------------------------------------------- /src/projen_view.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { 3 | ProjenDependency, 4 | ProjenInfo, 5 | ProjenStep, 6 | ProjenTask, 7 | } from "./projen_info"; 8 | 9 | type TreeNodeType = 10 | | vscode.TreeItem 11 | | Task 12 | | Step 13 | | File 14 | | Dependency 15 | | Project 16 | | void 17 | | null 18 | | undefined; 19 | 20 | export class ProjenView implements vscode.TreeDataProvider { 21 | public _onDidChangeTreeData: vscode.EventEmitter = 22 | new vscode.EventEmitter(); 23 | readonly onDidChangeTreeData: vscode.Event = 24 | this._onDidChangeTreeData.event; 25 | private tasks: Task[] = []; 26 | 27 | constructor(private projenInfos: ProjenInfo[]) {} 28 | 29 | getTreeItem(element: vscode.TreeItem): vscode.TreeItem { 30 | return element; 31 | } 32 | 33 | // list all projects 34 | async getChildrenRoot() { 35 | if (this.projenInfos.length === 1) { 36 | return this.getChildrenProjects(this.projenInfos[0]); 37 | } else { 38 | return Promise.resolve(this.projenInfos.map((i) => new Project(i))); 39 | } 40 | } 41 | async getChildrenProjects(info: ProjenInfo) { 42 | return Promise.resolve([ 43 | new BaseTreeItem(info, "Tasks", vscode.TreeItemCollapsibleState.Expanded), 44 | new BaseTreeItem( 45 | info, 46 | "Managed Files", 47 | vscode.TreeItemCollapsibleState.Collapsed 48 | ), 49 | new BaseTreeItem( 50 | info, 51 | "Dependencies", 52 | vscode.TreeItemCollapsibleState.Collapsed 53 | ), 54 | ]); 55 | } 56 | async getChildrenTasks(info: ProjenInfo) { 57 | return Promise.resolve( 58 | info.tasks.map((t) => { 59 | const task = new Task(t); 60 | this.tasks.push(task); 61 | return task; 62 | }) 63 | ); 64 | } 65 | async getChildrenSteps(info: ProjenInfo, currentTask: Task) { 66 | const task = info.tasks.find((t) => t.name === currentTask.label!)!; 67 | 68 | if (task.steps.length === 0) { 69 | return Promise.resolve([]); 70 | } 71 | 72 | return Promise.resolve( 73 | task.steps.map((s: ProjenStep) => { 74 | if (s.type === "spawn") { 75 | return this.tasks.find((t) => t.label! === s.value)!; 76 | } else { 77 | return new Step(info, s.value); 78 | } 79 | }) 80 | ); 81 | } 82 | async getChildrenDependencies(info: ProjenInfo) { 83 | return Promise.resolve( 84 | info.dependencies.map((dep: ProjenDependency) => { 85 | return new Dependency(dep); 86 | }) 87 | ); 88 | } 89 | async getChildrenManagedFiles(info: ProjenInfo) { 90 | return Promise.resolve( 91 | info.managedFiles.map((file: vscode.Uri) => new File(info, file)) 92 | ); 93 | } 94 | 95 | async getChildren(element?: TreeNodeType): Promise { 96 | if (!element) { 97 | return this.getChildrenRoot(); 98 | } else if (element instanceof Project) { 99 | return this.getChildrenProjects(element.projenInfo); 100 | } else if (element instanceof BaseTreeItem && element.label === "Tasks") { 101 | return this.getChildrenTasks(element.projenInfo); 102 | } else if ( 103 | element instanceof BaseTreeItem && 104 | element.label === "Managed Files" 105 | ) { 106 | return this.getChildrenManagedFiles(element.projenInfo); 107 | } else if ( 108 | element instanceof BaseTreeItem && 109 | element.label === "Dependencies" 110 | ) { 111 | return this.getChildrenDependencies(element.projenInfo); 112 | } else if (element instanceof Task) { 113 | return this.getChildrenSteps(element.projenInfo, element); 114 | } 115 | 116 | return Promise.resolve([]); 117 | } 118 | } 119 | 120 | class BaseTreeItem extends vscode.TreeItem { 121 | constructor( 122 | public readonly projenInfo: ProjenInfo, 123 | label: string | vscode.TreeItemLabel | vscode.Uri, 124 | collapsibleState: vscode.TreeItemCollapsibleState 125 | ) { 126 | super(label as any, collapsibleState); 127 | } 128 | } 129 | 130 | class Task extends BaseTreeItem { 131 | public projenInfo: ProjenInfo; 132 | constructor(obj: ProjenTask) { 133 | super( 134 | obj.projenInfo, 135 | obj.name, 136 | obj.steps.length === 0 137 | ? vscode.TreeItemCollapsibleState.None 138 | : vscode.TreeItemCollapsibleState.Collapsed 139 | ); 140 | this.projenInfo = obj.projenInfo; 141 | this.command = { 142 | title: "Run Task", 143 | command: "projen.runTask", 144 | arguments: [this.projenInfo, obj.name], 145 | }; 146 | this.tooltip = obj.description; 147 | this.iconPath = new vscode.ThemeIcon( 148 | "play", 149 | new vscode.ThemeColor("terminal.ansiGreen") 150 | ); 151 | } 152 | } 153 | 154 | class Step extends BaseTreeItem { 155 | constructor(projenInfo: ProjenInfo, text: string) { 156 | super(projenInfo, text, vscode.TreeItemCollapsibleState.None); 157 | 158 | this.tooltip = ""; 159 | this.iconPath = new vscode.ThemeIcon("testing-unset-icon"); 160 | } 161 | } 162 | 163 | class File extends BaseTreeItem { 164 | constructor(projenInfo: ProjenInfo, public readonly file: vscode.Uri) { 165 | super(projenInfo, file, vscode.TreeItemCollapsibleState.None); 166 | 167 | this.iconPath = vscode.ThemeIcon.File; 168 | } 169 | } 170 | 171 | class Project extends BaseTreeItem { 172 | constructor(info: ProjenInfo) { 173 | super(info, info.label, vscode.TreeItemCollapsibleState.Collapsed); 174 | 175 | this.iconPath = vscode.ThemeIcon.Folder; 176 | } 177 | } 178 | 179 | class Dependency extends BaseTreeItem { 180 | constructor(public readonly obj: ProjenDependency) { 181 | super( 182 | obj.projenInfo, 183 | `${obj.type}`.padEnd(9, " ") + 184 | "| " + 185 | (obj.version ? `${obj.name} [${obj.version}]` : obj.name), 186 | vscode.TreeItemCollapsibleState.None 187 | ); 188 | 189 | this.tooltip = ""; 190 | this.iconPath = new vscode.ThemeIcon("package"); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/projen_watcher.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ProjenInfo } from "./projen_info"; 3 | 4 | export class ProjenWatcher { 5 | readonly projenDirectoryWatcher: vscode.FileSystemWatcher; 6 | readonly projenFileWatcher: vscode.FileSystemWatcher; 7 | 8 | constructor(public projenInfo: ProjenInfo) { 9 | this.projenDirectoryWatcher = vscode.workspace.createFileSystemWatcher( 10 | new vscode.RelativePattern(this.projenInfo.projectRoot, ".projen/**"), 11 | false, 12 | false, 13 | false 14 | ); 15 | 16 | this.projenFileWatcher = vscode.workspace.createFileSystemWatcher( 17 | new vscode.RelativePattern( 18 | this.projenInfo.projectRoot, 19 | ".projenrc.{ts,js}" 20 | ), 21 | false, 22 | false, 23 | false 24 | ); 25 | } 26 | 27 | onDirectoryChange(listener: (e: vscode.Uri) => any) { 28 | this.projenDirectoryWatcher.onDidCreate(listener); 29 | this.projenDirectoryWatcher.onDidChange(listener); 30 | this.projenDirectoryWatcher.onDidDelete(listener); 31 | } 32 | 33 | onProjenChange(listener: (e: vscode.Uri) => any) { 34 | this.projenFileWatcher.onDidCreate(listener); 35 | this.projenFileWatcher.onDidChange(listener); 36 | this.projenFileWatcher.onDidDelete(listener); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | *.snap linguist-generated 4 | /.gitattributes linguist-generated 5 | /.github/pull_request_template.md linguist-generated 6 | /.github/workflows/build.yml linguist-generated 7 | /.github/workflows/pull-request-lint.yml linguist-generated 8 | /.github/workflows/release.yml linguist-generated 9 | /.github/workflows/stale.yml linguist-generated 10 | /.github/workflows/upgrade-main.yml linguist-generated 11 | /.gitignore linguist-generated 12 | /.mergify.yml linguist-generated 13 | /.npmignore linguist-generated 14 | /.projen/** linguist-generated 15 | /.projen/deps.json linguist-generated 16 | /.projen/files.json linguist-generated 17 | /.projen/tasks.json linguist-generated 18 | /LICENSE linguist-generated 19 | /package-lock.json linguist-generated 20 | /package.json linguist-generated -------------------------------------------------------------------------------- /test/other-sample-node-project/.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # -------------------------------------------------------------------------------- /test/other-sample-node-project/.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: build 4 | on: 5 | pull_request: {} 6 | workflow_dispatch: {} 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | checks: write 12 | contents: write 13 | actions: write 14 | env: 15 | CI: "true" 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | with: 20 | ref: ${{ github.event.pull_request.head.ref }} 21 | repository: ${{ github.event.pull_request.head.repo.full_name }} 22 | - name: Set git identity 23 | run: |- 24 | git config user.name "github-actions" 25 | git config user.email "github-actions@github.com" 26 | - name: Install dependencies 27 | run: npm ci 28 | - name: build 29 | run: npx projen build 30 | - name: Check for changes 31 | id: git_diff 32 | run: git diff --exit-code || echo "::set-output name=has_changes::true" 33 | - if: steps.git_diff.outputs.has_changes 34 | name: Commit and push changes (if changed) 35 | run: 'git add . && git commit -m "chore: self mutation" && git push origin 36 | HEAD:${{ github.event.pull_request.head.ref }}' 37 | - if: steps.git_diff.outputs.has_changes 38 | name: Update status check (if changed) 39 | run: gh api -X POST /repos/${{ github.event.pull_request.head.repo.full_name 40 | }}/check-runs -F name="build" -F head_sha="$(git rev-parse HEAD)" -F 41 | status="completed" -F conclusion="success" 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | - if: steps.git_diff.outputs.has_changes 45 | name: Cancel workflow (if changed) 46 | run: gh api -X POST /repos/${{ github.event.pull_request.head.repo.full_name 47 | }}/actions/runs/${{ github.run_id }}/cancel 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | jobs: 14 | validate: 15 | name: Validate PR title 16 | runs-on: ubuntu-latest 17 | permissions: 18 | pull-requests: write 19 | steps: 20 | - uses: amannn/action-semantic-pull-request@v3.4.6 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | types: |- 25 | feat 26 | fix 27 | chore 28 | requireScope: false 29 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: release 4 | on: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: {} 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | outputs: 15 | latest_commit: ${{ steps.git_remote.outputs.latest_commit }} 16 | env: 17 | CI: "true" 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | with: 22 | fetch-depth: 0 23 | - name: Set git identity 24 | run: |- 25 | git config user.name "github-actions" 26 | git config user.email "github-actions@github.com" 27 | - name: Install dependencies 28 | run: npm ci 29 | - name: release 30 | run: npx projen release 31 | - name: Check for new commits 32 | id: git_remote 33 | run: echo ::set-output name=latest_commit::"$(git ls-remote origin -h ${{ 34 | github.ref }} | cut -f1)" 35 | - name: Upload artifact 36 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} 37 | uses: actions/upload-artifact@v2.1.1 38 | with: 39 | name: dist 40 | path: dist 41 | release_github: 42 | name: Publish to GitHub Releases 43 | needs: release 44 | runs-on: ubuntu-latest 45 | permissions: 46 | contents: write 47 | if: needs.release.outputs.latest_commit == github.sha 48 | steps: 49 | - name: Download build artifacts 50 | uses: actions/download-artifact@v2 51 | with: 52 | name: dist 53 | path: dist 54 | - name: Release 55 | run: errout=$(mktemp); gh release create $(cat dist/releasetag.txt) -R 56 | $GITHUB_REPOSITORY -F dist/changelog.md -t $(cat dist/releasetag.txt) 57 | --target $GITHUB_REF 2> $errout && true; exitcode=$?; if [ $exitcode 58 | -ne 0 ] && ! grep -q "Release.tag_name already exists" $errout; then 59 | cat $errout; exit $exitcode; fi 60 | env: 61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | GITHUB_REPOSITORY: ${{ github.repository }} 63 | GITHUB_REF: ${{ github.ref }} 64 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: stale 4 | on: 5 | schedule: 6 | - cron: 0 1 * * * 7 | workflow_dispatch: {} 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | issues: write 13 | pull-requests: write 14 | steps: 15 | - uses: actions/stale@v4 16 | with: 17 | days-before-stale: -1 18 | days-before-close: -1 19 | days-before-pr-stale: 14 20 | days-before-pr-close: 2 21 | stale-pr-message: This pull request is now marked as stale because it hasn't 22 | seen activity for a while. Add a comment or it will be closed soon. 23 | close-pr-message: Closing this pull request as it hasn't seen activity for a 24 | while. Please add a comment @mentioning a maintainer to reopen. 25 | stale-pr-label: stale 26 | days-before-issue-stale: 60 27 | days-before-issue-close: 7 28 | stale-issue-message: This issue is now marked as stale because it hasn't seen 29 | activity for a while. Add a comment or it will be closed soon. 30 | close-issue-message: Closing this issue as it hasn't seen activity for a while. 31 | Please add a comment @mentioning a maintainer to reopen. 32 | stale-issue-label: stale 33 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.github/workflows/upgrade-main.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: upgrade-main 4 | on: 5 | workflow_dispatch: {} 6 | schedule: 7 | - cron: 0 0 * * * 8 | jobs: 9 | upgrade: 10 | name: Upgrade 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: read 14 | outputs: 15 | conclusion: ${{ steps.build.outputs.conclusion }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | with: 20 | ref: main 21 | - name: Set git identity 22 | run: |- 23 | git config user.name "github-actions" 24 | git config user.email "github-actions@github.com" 25 | - name: Install dependencies 26 | run: npm ci 27 | - name: Upgrade dependencies 28 | run: npx projen upgrade 29 | - name: Build 30 | id: build 31 | run: npx projen build && echo "::set-output name=conclusion::success" || echo 32 | "::set-output name=conclusion::failure" 33 | - name: Create Patch 34 | run: |- 35 | git add . 36 | git diff --patch --staged > .upgrade.tmp.patch 37 | - name: Upload patch 38 | uses: actions/upload-artifact@v2 39 | with: 40 | name: .upgrade.tmp.patch 41 | path: .upgrade.tmp.patch 42 | pr: 43 | name: Create Pull Request 44 | needs: upgrade 45 | runs-on: ubuntu-latest 46 | permissions: 47 | contents: write 48 | pull-requests: write 49 | checks: write 50 | steps: 51 | - name: Checkout 52 | uses: actions/checkout@v2 53 | with: 54 | ref: main 55 | - name: Set git identity 56 | run: |- 57 | git config user.name "github-actions" 58 | git config user.email "github-actions@github.com" 59 | - name: Download patch 60 | uses: actions/download-artifact@v2 61 | with: 62 | name: .upgrade.tmp.patch 63 | path: ${{ runner.temp }} 64 | - name: Apply patch 65 | run: '[ -s ${{ runner.temp }}/.upgrade.tmp.patch ] && git apply ${{ runner.temp 66 | }}/.upgrade.tmp.patch || echo "Empty patch. Skipping."' 67 | - name: Create Pull Request 68 | id: create-pr 69 | uses: peter-evans/create-pull-request@v3 70 | with: 71 | token: ${{ secrets.GITHUB_TOKEN }} 72 | commit-message: >- 73 | chore(deps): upgrade dependencies 74 | 75 | 76 | Upgrades project dependencies. See details in [workflow run]. 77 | 78 | 79 | [Workflow Run]: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} 80 | 81 | 82 | ------ 83 | 84 | 85 | *Automatically created by projen via the "upgrade-main" workflow* 86 | branch: github-actions/upgrade-main 87 | title: "chore(deps): upgrade dependencies" 88 | body: >- 89 | Upgrades project dependencies. See details in [workflow run]. 90 | 91 | 92 | [Workflow Run]: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} 93 | 94 | 95 | ------ 96 | 97 | 98 | *Automatically created by projen via the "upgrade-main" workflow* 99 | author: github-actions 100 | committer: github-actions 101 | signoff: true 102 | - name: Update status check 103 | if: steps.create-pr.outputs.pull-request-url != '' 104 | run: "curl -i --fail -X POST -H \"Accept: application/vnd.github.v3+json\" -H 105 | \"Authorization: token ${GITHUB_TOKEN}\" 106 | https://api.github.com/repos/${{ github.repository }}/check-runs -d 107 | '{\"name\":\"build\",\"head_sha\":\"github-actions/upgrade-main\",\"s\ 108 | tatus\":\"completed\",\"conclusion\":\"${{ 109 | needs.upgrade.outputs.conclusion }}\",\"output\":{\"title\":\"Created 110 | via the upgrade-main workflow.\",\"summary\":\"Action run URL: 111 | https://github.com/${{ github.repository }}/actions/runs/${{ 112 | github.run_id }}\"}}'" 113 | env: 114 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 115 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.gitignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | !/.gitattributes 3 | !/.projen/tasks.json 4 | !/.projen/deps.json 5 | !/.projen/files.json 6 | !/.github/workflows/pull-request-lint.yml 7 | !/.github/workflows/stale.yml 8 | !/package.json 9 | !/LICENSE 10 | !/.npmignore 11 | logs 12 | *.log 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | lerna-debug.log* 17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | lib-cov 23 | coverage 24 | *.lcov 25 | .nyc_output 26 | build/Release 27 | node_modules/ 28 | jspm_packages/ 29 | *.tsbuildinfo 30 | .eslintcache 31 | *.tgz 32 | .yarn-integrity 33 | .cache 34 | !/.projenrc.js 35 | /test-reports/ 36 | junit.xml 37 | /coverage/ 38 | !/.github/workflows/build.yml 39 | /dist/changelog.md 40 | /dist/version.txt 41 | !/.github/workflows/release.yml 42 | !/.mergify.yml 43 | !/.github/pull_request_template.md 44 | !/.github/workflows/upgrade-main.yml 45 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.mergify.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | pull_request_rules: 4 | - name: Automatic merge on approval and successful build 5 | actions: 6 | merge: 7 | method: squash 8 | commit_message: title+body 9 | strict: smart 10 | strict_method: merge 11 | delete_head_branch: {} 12 | conditions: 13 | - "#approved-reviews-by>=1" 14 | - -label~=(do-not-merge) 15 | - status-success=build 16 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | /.projenrc.js 3 | /.projen/ 4 | /test-reports/ 5 | junit.xml 6 | /coverage/ 7 | /dist/changelog.md 8 | /dist/version.txt 9 | /.mergify.yml 10 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.projen/deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "jest", 5 | "type": "build" 6 | }, 7 | { 8 | "name": "jest-junit", 9 | "version": "^13", 10 | "type": "build" 11 | }, 12 | { 13 | "name": "npm-check-updates", 14 | "version": "^11", 15 | "type": "build" 16 | }, 17 | { 18 | "name": "projen", 19 | "type": "build" 20 | }, 21 | { 22 | "name": "standard-version", 23 | "version": "^9", 24 | "type": "build" 25 | } 26 | ], 27 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 28 | } 29 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".gitattributes", 4 | ".github/pull_request_template.md", 5 | ".github/workflows/build.yml", 6 | ".github/workflows/pull-request-lint.yml", 7 | ".github/workflows/release.yml", 8 | ".github/workflows/stale.yml", 9 | ".github/workflows/upgrade-main.yml", 10 | ".gitignore", 11 | ".mergify.yml", 12 | ".npmignore", 13 | ".projen/deps.json", 14 | ".projen/files.json", 15 | ".projen/tasks.json", 16 | "LICENSE" 17 | ], 18 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 19 | } 20 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.projen/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "build": { 4 | "name": "build", 5 | "description": "Full release build", 6 | "steps": [ 7 | { 8 | "spawn": "default" 9 | }, 10 | { 11 | "spawn": "pre-compile" 12 | }, 13 | { 14 | "spawn": "compile" 15 | }, 16 | { 17 | "spawn": "post-compile" 18 | }, 19 | { 20 | "spawn": "test" 21 | }, 22 | { 23 | "spawn": "package" 24 | } 25 | ] 26 | }, 27 | "bump": { 28 | "name": "bump", 29 | "description": "Bumps version based on latest git tag and generates a changelog entry", 30 | "env": { 31 | "OUTFILE": "package.json", 32 | "CHANGELOG": "dist/changelog.md", 33 | "BUMPFILE": "dist/version.txt", 34 | "RELEASETAG": "dist/releasetag.txt" 35 | }, 36 | "steps": [ 37 | { 38 | "builtin": "release/bump-version" 39 | } 40 | ], 41 | "condition": "! git log --oneline -1 | grep -q \"chore(release):\"" 42 | }, 43 | "clobber": { 44 | "name": "clobber", 45 | "description": "hard resets to HEAD of origin and cleans the local repo", 46 | "env": { 47 | "BRANCH": "$(git branch --show-current)" 48 | }, 49 | "steps": [ 50 | { 51 | "exec": "git checkout -b scratch", 52 | "name": "save current HEAD in \"scratch\" branch" 53 | }, 54 | { 55 | "exec": "git checkout $BRANCH" 56 | }, 57 | { 58 | "exec": "git fetch origin", 59 | "name": "fetch latest changes from origin" 60 | }, 61 | { 62 | "exec": "git reset --hard origin/$BRANCH", 63 | "name": "hard reset to origin commit" 64 | }, 65 | { 66 | "exec": "git clean -fdx", 67 | "name": "clean all untracked files" 68 | }, 69 | { 70 | "say": "ready to rock! (unpushed commits are under the \"scratch\" branch)" 71 | } 72 | ], 73 | "condition": "git diff --exit-code > /dev/null" 74 | }, 75 | "compile": { 76 | "name": "compile", 77 | "description": "Only compile" 78 | }, 79 | "default": { 80 | "name": "default", 81 | "description": "Synthesize project files", 82 | "steps": [ 83 | { 84 | "exec": "node .projenrc.js" 85 | } 86 | ] 87 | }, 88 | "package": { 89 | "name": "package", 90 | "description": "Creates the distribution package" 91 | }, 92 | "post-compile": { 93 | "name": "post-compile", 94 | "description": "Runs after successful compilation" 95 | }, 96 | "pre-compile": { 97 | "name": "pre-compile", 98 | "description": "Prepare the project for compilation" 99 | }, 100 | "release": { 101 | "name": "release", 102 | "description": "Prepare a release from \"main\" branch", 103 | "env": { 104 | "RELEASE": "true" 105 | }, 106 | "steps": [ 107 | { 108 | "exec": "rm -fr dist" 109 | }, 110 | { 111 | "spawn": "bump" 112 | }, 113 | { 114 | "spawn": "build" 115 | }, 116 | { 117 | "spawn": "unbump" 118 | }, 119 | { 120 | "exec": "git diff --ignore-space-at-eol --exit-code" 121 | } 122 | ] 123 | }, 124 | "test": { 125 | "name": "test", 126 | "description": "Run tests", 127 | "steps": [ 128 | { 129 | "exec": "jest --passWithNoTests --all --updateSnapshot" 130 | } 131 | ] 132 | }, 133 | "test:update": { 134 | "name": "test:update", 135 | "description": "Update jest snapshots", 136 | "steps": [ 137 | { 138 | "exec": "jest --updateSnapshot" 139 | } 140 | ] 141 | }, 142 | "test:watch": { 143 | "name": "test:watch", 144 | "description": "Run jest in watch mode", 145 | "steps": [ 146 | { 147 | "exec": "jest --watch" 148 | } 149 | ] 150 | }, 151 | "unbump": { 152 | "name": "unbump", 153 | "description": "Restores version to 0.0.0", 154 | "env": { 155 | "OUTFILE": "package.json", 156 | "CHANGELOG": "dist/changelog.md", 157 | "BUMPFILE": "dist/version.txt", 158 | "RELEASETAG": "dist/releasetag.txt" 159 | }, 160 | "steps": [ 161 | { 162 | "builtin": "release/reset-version" 163 | } 164 | ] 165 | }, 166 | "upgrade": { 167 | "name": "upgrade", 168 | "description": "upgrade dependencies", 169 | "env": { 170 | "CI": "0" 171 | }, 172 | "steps": [ 173 | { 174 | "exec": "npm-check-updates --dep dev --upgrade --target=minor --reject='projen'" 175 | }, 176 | { 177 | "exec": "npm-check-updates --dep optional --upgrade --target=minor --reject='projen'" 178 | }, 179 | { 180 | "exec": "npm-check-updates --dep peer --upgrade --target=minor --reject='projen'" 181 | }, 182 | { 183 | "exec": "npm-check-updates --dep prod --upgrade --target=minor --reject='projen'" 184 | }, 185 | { 186 | "exec": "npm-check-updates --dep bundle --upgrade --target=minor --reject='projen'" 187 | }, 188 | { 189 | "exec": "npm install" 190 | }, 191 | { 192 | "exec": "npm update jest jest-junit npm-check-updates standard-version" 193 | }, 194 | { 195 | "exec": "npx projen" 196 | } 197 | ] 198 | }, 199 | "upgrade-projen": { 200 | "name": "upgrade-projen", 201 | "description": "upgrade projen", 202 | "env": { 203 | "CI": "0" 204 | }, 205 | "steps": [ 206 | { 207 | "exec": "npm-check-updates --dep dev --upgrade --target=minor --filter='projen'" 208 | }, 209 | { 210 | "exec": "npm-check-updates --dep optional --upgrade --target=minor --filter='projen'" 211 | }, 212 | { 213 | "exec": "npm-check-updates --dep peer --upgrade --target=minor --filter='projen'" 214 | }, 215 | { 216 | "exec": "npm-check-updates --dep prod --upgrade --target=minor --filter='projen'" 217 | }, 218 | { 219 | "exec": "npm-check-updates --dep bundle --upgrade --target=minor --filter='projen'" 220 | }, 221 | { 222 | "exec": "npm install" 223 | }, 224 | { 225 | "exec": "npm update projen" 226 | }, 227 | { 228 | "exec": "npx projen" 229 | } 230 | ] 231 | } 232 | }, 233 | "env": { 234 | "PATH": "$(npx -c \"node -e \\\"console.log(process.env.PATH)\\\"\")" 235 | }, 236 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 237 | } 238 | -------------------------------------------------------------------------------- /test/other-sample-node-project/.projenrc.js: -------------------------------------------------------------------------------- 1 | const { javascript } = require("projen"); 2 | const project = new javascript.NodeProject({ 3 | defaultReleaseBranch: "main", 4 | name: "sample-node-project", 5 | packageManager: javascript.NodePackageManager.NPM, 6 | 7 | // deps: [], /* Runtime dependencies of this module. */ 8 | // description: undefined, /* The description is just a string that helps people understand the purpose of the package. */ 9 | // devDeps: [], /* Build dependencies for this module. */ 10 | // packageName: undefined, /* The "name" in package.json. */ 11 | // release: undefined, /* Add release management to this project. */ 12 | }); 13 | project.synth(); -------------------------------------------------------------------------------- /test/other-sample-node-project/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /test/other-sample-node-project/README.md: -------------------------------------------------------------------------------- 1 | # replace this -------------------------------------------------------------------------------- /test/other-sample-node-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-node-project", 3 | "scripts": { 4 | "build": "npx projen build", 5 | "bump": "npx projen bump", 6 | "clobber": "npx projen clobber", 7 | "compile": "npx projen compile", 8 | "default": "npx projen default", 9 | "package": "npx projen package", 10 | "post-compile": "npx projen post-compile", 11 | "pre-compile": "npx projen pre-compile", 12 | "release": "npx projen release", 13 | "test": "npx projen test", 14 | "test:update": "npx projen test:update", 15 | "test:watch": "npx projen test:watch", 16 | "unbump": "npx projen unbump", 17 | "upgrade": "npx projen upgrade", 18 | "upgrade-projen": "npx projen upgrade-projen", 19 | "projen": "npx projen" 20 | }, 21 | "devDependencies": { 22 | "jest": "^27.4.3", 23 | "jest-junit": "^13", 24 | "npm-check-updates": "^11", 25 | "projen": "^0.40.4", 26 | "standard-version": "^9" 27 | }, 28 | "bundledDependencies": [], 29 | "main": "lib/index.js", 30 | "license": "Apache-2.0", 31 | "version": "0.0.0", 32 | "jest": { 33 | "clearMocks": true, 34 | "collectCoverage": true, 35 | "coverageReporters": [ 36 | "json", 37 | "lcov", 38 | "clover", 39 | "text" 40 | ], 41 | "coverageDirectory": "coverage", 42 | "coveragePathIgnorePatterns": [ 43 | "/node_modules/" 44 | ], 45 | "testPathIgnorePatterns": [ 46 | "/node_modules/" 47 | ], 48 | "watchPathIgnorePatterns": [ 49 | "/node_modules/" 50 | ], 51 | "testMatch": [ 52 | "**/__tests__/**/*.[jt]s?(x)", 53 | "**/?(*.)+(spec|test).[tj]s?(x)" 54 | ], 55 | "reporters": [ 56 | "default", 57 | [ 58 | "jest-junit", 59 | { 60 | "outputDirectory": "test-reports" 61 | } 62 | ] 63 | ] 64 | }, 65 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 66 | } -------------------------------------------------------------------------------- /test/sample-node-project/.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | *.snap linguist-generated 4 | /.gitattributes linguist-generated 5 | /.github/pull_request_template.md linguist-generated 6 | /.github/workflows/build.yml linguist-generated 7 | /.github/workflows/pull-request-lint.yml linguist-generated 8 | /.github/workflows/release.yml linguist-generated 9 | /.github/workflows/upgrade-main.yml linguist-generated 10 | /.gitignore linguist-generated 11 | /.mergify.yml linguist-generated 12 | /.npmignore linguist-generated 13 | /.projen/** linguist-generated 14 | /.projen/deps.json linguist-generated 15 | /.projen/files.json linguist-generated 16 | /.projen/tasks.json linguist-generated 17 | /LICENSE linguist-generated 18 | /package-lock.json linguist-generated 19 | /package.json linguist-generated -------------------------------------------------------------------------------- /test/sample-node-project/.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # -------------------------------------------------------------------------------- /test/sample-node-project/.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: build 4 | on: 5 | pull_request: {} 6 | workflow_dispatch: {} 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: write 12 | outputs: 13 | self_mutation_happened: ${{ steps.self_mutation.outputs.self_mutation_happened }} 14 | env: 15 | CI: "true" 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | with: 20 | ref: ${{ github.event.pull_request.head.ref }} 21 | repository: ${{ github.event.pull_request.head.repo.full_name }} 22 | - name: Install dependencies 23 | run: npm install 24 | - name: build 25 | run: npx projen build 26 | - id: self_mutation 27 | name: Find mutations 28 | run: |- 29 | git add . 30 | git diff --staged --patch --exit-code > .repo.patch || echo "::set-output name=self_mutation_happened::true" 31 | - if: steps.self_mutation.outputs.self_mutation_happened 32 | name: Upload patch 33 | uses: actions/upload-artifact@v2 34 | with: 35 | name: .repo.patch 36 | path: .repo.patch 37 | - name: Fail build on mutation 38 | if: steps.self_mutation.outputs.self_mutation_happened 39 | run: |- 40 | echo "::error::Files were changed during build (see build log). If this was triggered from a fork, you will need to update your branch." 41 | cat .repo.patch 42 | exit 1 43 | self-mutation: 44 | needs: build 45 | runs-on: ubuntu-latest 46 | permissions: 47 | contents: write 48 | if: always() && needs.build.outputs.self_mutation_happened && !(github.event.pull_request.head.repo.full_name != github.repository) 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v2 52 | with: 53 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 54 | ref: ${{ github.event.pull_request.head.ref }} 55 | repository: ${{ github.event.pull_request.head.repo.full_name }} 56 | - name: Download patch 57 | uses: actions/download-artifact@v2 58 | with: 59 | name: .repo.patch 60 | path: ${{ runner.temp }} 61 | - name: Apply patch 62 | run: '[ -s ${{ runner.temp }}/.repo.patch ] && git apply ${{ runner.temp }}/.repo.patch || echo "Empty patch. Skipping."' 63 | - name: Set git identity 64 | run: |- 65 | git config user.name "github-actions" 66 | git config user.email "github-actions@github.com" 67 | - name: Push changes 68 | run: |2- 69 | git add . 70 | git commit -s -m "chore: self mutation" 71 | git push origin HEAD:${{ github.event.pull_request.head.ref }} 72 | -------------------------------------------------------------------------------- /test/sample-node-project/.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | jobs: 14 | validate: 15 | name: Validate PR title 16 | runs-on: ubuntu-latest 17 | permissions: 18 | pull-requests: write 19 | steps: 20 | - uses: amannn/action-semantic-pull-request@v3.4.6 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | types: |- 25 | feat 26 | fix 27 | chore 28 | requireScope: false 29 | -------------------------------------------------------------------------------- /test/sample-node-project/.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: release 4 | on: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: {} 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | outputs: 15 | latest_commit: ${{ steps.git_remote.outputs.latest_commit }} 16 | env: 17 | CI: "true" 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | with: 22 | fetch-depth: 0 23 | - name: Set git identity 24 | run: |- 25 | git config user.name "github-actions" 26 | git config user.email "github-actions@github.com" 27 | - name: Install dependencies 28 | run: npm ci 29 | - name: release 30 | run: npx projen release 31 | - name: Check for new commits 32 | id: git_remote 33 | run: echo ::set-output name=latest_commit::"$(git ls-remote origin -h ${{ github.ref }} | cut -f1)" 34 | - name: Upload artifact 35 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} 36 | uses: actions/upload-artifact@v2.1.1 37 | with: 38 | name: build-artifact 39 | path: dist 40 | release_github: 41 | name: Publish to GitHub Releases 42 | needs: release 43 | runs-on: ubuntu-latest 44 | permissions: 45 | contents: write 46 | if: needs.release.outputs.latest_commit == github.sha 47 | steps: 48 | - uses: actions/setup-node@v2 49 | with: 50 | node-version: 14.x 51 | - name: Download build artifacts 52 | uses: actions/download-artifact@v2 53 | with: 54 | name: build-artifact 55 | path: dist 56 | - name: Release 57 | run: errout=$(mktemp); gh release create $(cat dist/releasetag.txt) -R $GITHUB_REPOSITORY -F dist/changelog.md -t $(cat dist/releasetag.txt) --target $GITHUB_REF 2> $errout && true; exitcode=$?; if [ $exitcode -ne 0 ] && ! grep -q "Release.tag_name already exists" $errout; then cat $errout; exit $exitcode; fi 58 | env: 59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | GITHUB_REPOSITORY: ${{ github.repository }} 61 | GITHUB_REF: ${{ github.ref }} 62 | -------------------------------------------------------------------------------- /test/sample-node-project/.github/workflows/upgrade-main.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: upgrade-main 4 | on: 5 | workflow_dispatch: {} 6 | schedule: 7 | - cron: 0 0 * * * 8 | jobs: 9 | upgrade: 10 | name: Upgrade 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: read 14 | outputs: 15 | patch_created: ${{ steps.create_patch.outputs.patch_created }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | with: 20 | ref: main 21 | - name: Install dependencies 22 | run: npm ci 23 | - name: Upgrade dependencies 24 | run: npx projen upgrade 25 | - id: create_patch 26 | name: Find mutations 27 | run: |- 28 | git add . 29 | git diff --staged --patch --exit-code > .repo.patch || echo "::set-output name=patch_created::true" 30 | - if: steps.create_patch.outputs.patch_created 31 | name: Upload patch 32 | uses: actions/upload-artifact@v2 33 | with: 34 | name: .repo.patch 35 | path: .repo.patch 36 | pr: 37 | name: Create Pull Request 38 | needs: upgrade 39 | runs-on: ubuntu-latest 40 | permissions: 41 | contents: write 42 | pull-requests: write 43 | if: ${{ needs.upgrade.outputs.patch_created }} 44 | steps: 45 | - name: Checkout 46 | uses: actions/checkout@v2 47 | with: 48 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 49 | ref: main 50 | - name: Download patch 51 | uses: actions/download-artifact@v2 52 | with: 53 | name: .repo.patch 54 | path: ${{ runner.temp }} 55 | - name: Apply patch 56 | run: '[ -s ${{ runner.temp }}/.repo.patch ] && git apply ${{ runner.temp }}/.repo.patch || echo "Empty patch. Skipping."' 57 | - name: Set git identity 58 | run: |- 59 | git config user.name "github-actions" 60 | git config user.email "github-actions@github.com" 61 | - name: Create Pull Request 62 | id: create-pr 63 | uses: peter-evans/create-pull-request@v3 64 | with: 65 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 66 | commit-message: |- 67 | chore(deps): upgrade dependencies 68 | 69 | Upgrades project dependencies. See details in [workflow run]. 70 | 71 | [Workflow Run]: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} 72 | 73 | ------ 74 | 75 | *Automatically created by projen via the "upgrade-main" workflow* 76 | branch: github-actions/upgrade-main 77 | title: "chore(deps): upgrade dependencies" 78 | body: |- 79 | Upgrades project dependencies. See details in [workflow run]. 80 | 81 | [Workflow Run]: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} 82 | 83 | ------ 84 | 85 | *Automatically created by projen via the "upgrade-main" workflow* 86 | author: github-actions 87 | committer: github-actions 88 | signoff: true 89 | -------------------------------------------------------------------------------- /test/sample-node-project/.gitignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | !/.gitattributes 3 | !/.projen/tasks.json 4 | !/.projen/deps.json 5 | !/.projen/files.json 6 | !/.github/workflows/pull-request-lint.yml 7 | !/package.json 8 | !/LICENSE 9 | !/.npmignore 10 | logs 11 | *.log 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | lerna-debug.log* 16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | lib-cov 22 | coverage 23 | *.lcov 24 | .nyc_output 25 | build/Release 26 | node_modules/ 27 | jspm_packages/ 28 | *.tsbuildinfo 29 | .eslintcache 30 | *.tgz 31 | .yarn-integrity 32 | .cache 33 | !/.projenrc.js 34 | /test-reports/ 35 | junit.xml 36 | /coverage/ 37 | !/.github/workflows/build.yml 38 | /dist/changelog.md 39 | /dist/version.txt 40 | !/.github/workflows/release.yml 41 | !/.mergify.yml 42 | !/.github/workflows/upgrade-main.yml 43 | !/.github/pull_request_template.md 44 | -------------------------------------------------------------------------------- /test/sample-node-project/.mergify.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | queue_rules: 4 | - name: default 5 | conditions: 6 | - "#approved-reviews-by>=1" 7 | - -label~=(do-not-merge) 8 | - status-success=build 9 | pull_request_rules: 10 | - name: Automatic merge on approval and successful build 11 | actions: 12 | delete_head_branch: {} 13 | queue: 14 | method: squash 15 | name: default 16 | commit_message_template: |- 17 | {{ title }} (#{{ number }}) 18 | 19 | {{ body }} 20 | conditions: 21 | - "#approved-reviews-by>=1" 22 | - -label~=(do-not-merge) 23 | - status-success=build 24 | -------------------------------------------------------------------------------- /test/sample-node-project/.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | /.projenrc.js 3 | /.projen/ 4 | /test-reports/ 5 | junit.xml 6 | /coverage/ 7 | /dist/changelog.md 8 | /dist/version.txt 9 | /.mergify.yml 10 | -------------------------------------------------------------------------------- /test/sample-node-project/.projen/deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "jest-junit", 5 | "version": "^13", 6 | "type": "build" 7 | }, 8 | { 9 | "name": "jest", 10 | "version": "^27", 11 | "type": "build" 12 | }, 13 | { 14 | "name": "npm-check-updates", 15 | "version": "^12", 16 | "type": "build" 17 | }, 18 | { 19 | "name": "projen", 20 | "type": "build" 21 | }, 22 | { 23 | "name": "standard-version", 24 | "version": "^9", 25 | "type": "build" 26 | } 27 | ], 28 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 29 | } 30 | -------------------------------------------------------------------------------- /test/sample-node-project/.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".gitattributes", 4 | ".github/pull_request_template.md", 5 | ".github/workflows/build.yml", 6 | ".github/workflows/pull-request-lint.yml", 7 | ".github/workflows/release.yml", 8 | ".github/workflows/upgrade-main.yml", 9 | ".gitignore", 10 | ".mergify.yml", 11 | ".npmignore", 12 | ".projen/deps.json", 13 | ".projen/files.json", 14 | ".projen/tasks.json", 15 | "LICENSE" 16 | ], 17 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 18 | } 19 | -------------------------------------------------------------------------------- /test/sample-node-project/.projen/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "build": { 4 | "name": "build", 5 | "description": "Full release build", 6 | "steps": [ 7 | { 8 | "spawn": "default" 9 | }, 10 | { 11 | "spawn": "pre-compile" 12 | }, 13 | { 14 | "spawn": "compile" 15 | }, 16 | { 17 | "spawn": "post-compile" 18 | }, 19 | { 20 | "spawn": "test" 21 | }, 22 | { 23 | "spawn": "package" 24 | } 25 | ] 26 | }, 27 | "bump": { 28 | "name": "bump", 29 | "description": "Bumps version based on latest git tag and generates a changelog entry", 30 | "env": { 31 | "OUTFILE": "package.json", 32 | "CHANGELOG": "dist/changelog.md", 33 | "BUMPFILE": "dist/version.txt", 34 | "RELEASETAG": "dist/releasetag.txt", 35 | "RELEASE_TAG_PREFIX": "" 36 | }, 37 | "steps": [ 38 | { 39 | "builtin": "release/bump-version" 40 | } 41 | ], 42 | "condition": "! git log --oneline -1 | grep -q \"chore(release):\"" 43 | }, 44 | "clobber": { 45 | "name": "clobber", 46 | "description": "hard resets to HEAD of origin and cleans the local repo", 47 | "env": { 48 | "BRANCH": "$(git branch --show-current)" 49 | }, 50 | "steps": [ 51 | { 52 | "exec": "git checkout -b scratch", 53 | "name": "save current HEAD in \"scratch\" branch" 54 | }, 55 | { 56 | "exec": "git checkout $BRANCH" 57 | }, 58 | { 59 | "exec": "git fetch origin", 60 | "name": "fetch latest changes from origin" 61 | }, 62 | { 63 | "exec": "git reset --hard origin/$BRANCH", 64 | "name": "hard reset to origin commit" 65 | }, 66 | { 67 | "exec": "git clean -fdx", 68 | "name": "clean all untracked files" 69 | }, 70 | { 71 | "say": "ready to rock! (unpushed commits are under the \"scratch\" branch)" 72 | } 73 | ], 74 | "condition": "git diff --exit-code > /dev/null" 75 | }, 76 | "compile": { 77 | "name": "compile", 78 | "description": "Only compile" 79 | }, 80 | "default": { 81 | "name": "default", 82 | "description": "Synthesize project files", 83 | "steps": [ 84 | { 85 | "exec": "node .projenrc.js" 86 | } 87 | ] 88 | }, 89 | "eject": { 90 | "name": "eject", 91 | "description": "Remove projen from the project", 92 | "env": { 93 | "PROJEN_EJECTING": "true" 94 | }, 95 | "steps": [ 96 | { 97 | "spawn": "default" 98 | } 99 | ] 100 | }, 101 | "package": { 102 | "name": "package", 103 | "description": "Creates the distribution package", 104 | "steps": [ 105 | { 106 | "exec": "mkdir -p dist\\js" 107 | }, 108 | { 109 | "exec": "mv $(npm pack) dist\\js/" 110 | } 111 | ] 112 | }, 113 | "post-compile": { 114 | "name": "post-compile", 115 | "description": "Runs after successful compilation" 116 | }, 117 | "post-upgrade": { 118 | "name": "post-upgrade", 119 | "description": "Runs after upgrading dependencies" 120 | }, 121 | "pre-compile": { 122 | "name": "pre-compile", 123 | "description": "Prepare the project for compilation" 124 | }, 125 | "release": { 126 | "name": "release", 127 | "description": "Prepare a release from \"main\" branch", 128 | "env": { 129 | "RELEASE": "true" 130 | }, 131 | "steps": [ 132 | { 133 | "exec": "rm -fr dist" 134 | }, 135 | { 136 | "spawn": "bump" 137 | }, 138 | { 139 | "spawn": "build" 140 | }, 141 | { 142 | "spawn": "unbump" 143 | }, 144 | { 145 | "exec": "git diff --ignore-space-at-eol --exit-code" 146 | } 147 | ] 148 | }, 149 | "test": { 150 | "name": "test", 151 | "description": "Run tests", 152 | "steps": [ 153 | { 154 | "exec": "jest --passWithNoTests --all --updateSnapshot" 155 | } 156 | ] 157 | }, 158 | "test:update": { 159 | "name": "test:update", 160 | "description": "Update jest snapshots", 161 | "steps": [ 162 | { 163 | "exec": "jest --updateSnapshot" 164 | } 165 | ] 166 | }, 167 | "test:watch": { 168 | "name": "test:watch", 169 | "description": "Run jest in watch mode", 170 | "steps": [ 171 | { 172 | "exec": "jest --watch" 173 | } 174 | ] 175 | }, 176 | "unbump": { 177 | "name": "unbump", 178 | "description": "Restores version to 0.0.0", 179 | "env": { 180 | "OUTFILE": "package.json", 181 | "CHANGELOG": "dist/changelog.md", 182 | "BUMPFILE": "dist/version.txt", 183 | "RELEASETAG": "dist/releasetag.txt", 184 | "RELEASE_TAG_PREFIX": "" 185 | }, 186 | "steps": [ 187 | { 188 | "builtin": "release/reset-version" 189 | } 190 | ] 191 | }, 192 | "upgrade": { 193 | "name": "upgrade", 194 | "description": "upgrade dependencies", 195 | "env": { 196 | "CI": "0" 197 | }, 198 | "steps": [ 199 | { 200 | "exec": "npm update npm-check-updates" 201 | }, 202 | { 203 | "exec": "npm-check-updates --dep dev --upgrade --target=minor" 204 | }, 205 | { 206 | "exec": "npm-check-updates --dep optional --upgrade --target=minor" 207 | }, 208 | { 209 | "exec": "npm-check-updates --dep peer --upgrade --target=minor" 210 | }, 211 | { 212 | "exec": "npm-check-updates --dep prod --upgrade --target=minor" 213 | }, 214 | { 215 | "exec": "npm-check-updates --dep bundle --upgrade --target=minor" 216 | }, 217 | { 218 | "exec": "npm install" 219 | }, 220 | { 221 | "exec": "npm update" 222 | }, 223 | { 224 | "exec": "npx projen" 225 | }, 226 | { 227 | "spawn": "post-upgrade" 228 | } 229 | ] 230 | } 231 | }, 232 | "env": { 233 | "PATH": "$(npx -c \"node -e \\\"console.log(process.env.PATH)\\\"\")" 234 | }, 235 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 236 | } 237 | -------------------------------------------------------------------------------- /test/sample-node-project/.projenrc.js: -------------------------------------------------------------------------------- 1 | const { javascript } = require("projen"); 2 | const project = new javascript.NodeProject({ 3 | defaultReleaseBranch: "main", 4 | name: "sample-node-project", 5 | packageManager: javascript.NodePackageManager.NPM, 6 | 7 | // deps: [], /* Runtime dependencies of this module. */ 8 | // description: undefined, /* The description is just a string that helps people understand the purpose of the package. */ 9 | // devDeps: [], /* Build dependencies for this module. */ 10 | // packageName: undefined, /* The "name" in package.json. */ 11 | // release: undefined, /* Add release management to this project. */ 12 | }); 13 | project.synth(); -------------------------------------------------------------------------------- /test/sample-node-project/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /test/sample-node-project/README.md: -------------------------------------------------------------------------------- 1 | # replace this -------------------------------------------------------------------------------- /test/sample-node-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-node-project", 3 | "scripts": { 4 | "build": "npx projen build", 5 | "bump": "npx projen bump", 6 | "clobber": "npx projen clobber", 7 | "compile": "npx projen compile", 8 | "default": "npx projen default", 9 | "eject": "npx projen eject", 10 | "package": "npx projen package", 11 | "post-compile": "npx projen post-compile", 12 | "post-upgrade": "npx projen post-upgrade", 13 | "pre-compile": "npx projen pre-compile", 14 | "release": "npx projen release", 15 | "test": "npx projen test", 16 | "test:update": "npx projen test:update", 17 | "test:watch": "npx projen test:watch", 18 | "unbump": "npx projen unbump", 19 | "upgrade": "npx projen upgrade", 20 | "projen": "npx projen" 21 | }, 22 | "devDependencies": { 23 | "jest": "^27", 24 | "jest-junit": "^13", 25 | "npm-check-updates": "^12", 26 | "projen": "^0.54.56", 27 | "standard-version": "^9" 28 | }, 29 | "main": "lib/index.js", 30 | "license": "Apache-2.0", 31 | "version": "0.0.0", 32 | "jest": { 33 | "clearMocks": true, 34 | "collectCoverage": true, 35 | "coverageReporters": [ 36 | "json", 37 | "lcov", 38 | "clover", 39 | "cobertura", 40 | "text" 41 | ], 42 | "coverageDirectory": "coverage", 43 | "coveragePathIgnorePatterns": [ 44 | "/node_modules/" 45 | ], 46 | "testPathIgnorePatterns": [ 47 | "/node_modules/" 48 | ], 49 | "watchPathIgnorePatterns": [ 50 | "/node_modules/" 51 | ], 52 | "testMatch": [ 53 | "**/__tests__/**/*.[jt]s?(x)", 54 | "**/?(*.)+(spec|test).[tj]s?(x)" 55 | ], 56 | "reporters": [ 57 | "default", 58 | [ 59 | "jest-junit", 60 | { 61 | "outputDirectory": "test-reports" 62 | } 63 | ] 64 | ] 65 | }, 66 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 67 | } 68 | -------------------------------------------------------------------------------- /tsconfig.dev.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "compilerOptions": { 4 | "alwaysStrict": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "experimentalDecorators": true, 8 | "inlineSourceMap": true, 9 | "inlineSources": true, 10 | "lib": [ 11 | "es2021", 12 | "dom" 13 | ], 14 | "module": "CommonJS", 15 | "noEmitOnError": false, 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitAny": true, 18 | "noImplicitReturns": true, 19 | "noImplicitThis": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "resolveJsonModule": true, 23 | "strict": true, 24 | "strictNullChecks": true, 25 | "strictPropertyInitialization": true, 26 | "stripInternal": true, 27 | "target": "ES2019" 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "test/**/*.ts", 32 | ".projenrc.ts", 33 | "projenrc/**/*.ts" 34 | ], 35 | "exclude": [ 36 | "node_modules" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib", 6 | "alwaysStrict": true, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "inlineSourceMap": true, 11 | "inlineSources": true, 12 | "lib": [ 13 | "es2021", 14 | "dom" 15 | ], 16 | "module": "CommonJS", 17 | "noEmitOnError": false, 18 | "noFallthroughCasesInSwitch": true, 19 | "noImplicitAny": true, 20 | "noImplicitReturns": true, 21 | "noImplicitThis": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "resolveJsonModule": true, 25 | "strict": true, 26 | "strictNullChecks": true, 27 | "strictPropertyInitialization": true, 28 | "stripInternal": true, 29 | "target": "ES2019" 30 | }, 31 | "include": [ 32 | "src/**/*.ts" 33 | ], 34 | "exclude": [] 35 | } 36 | --------------------------------------------------------------------------------