├── .commitlintrc.js ├── .eslintrc.js ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── config.yml ├── actions │ ├── create-check │ │ └── action.yml │ └── install-latest-npm │ │ └── action.yml ├── dependabot.yml ├── matchers │ └── tap.json ├── settings.yml └── workflows │ ├── audit.yml │ ├── ci-release.yml │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── post-dependabot.yml │ ├── pull-request.yml │ ├── release-integration.yml │ └── release.yml ├── .gitignore ├── .npmrc ├── .release-please-manifest.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── lib ├── default-input.js └── init-package-json.js ├── package.json ├── release-please-config.json └── test ├── basic.js ├── bins.js ├── dependencies.js ├── fixtures ├── basic.fixture.js └── setup.js ├── license.js ├── name-default-formatting.js ├── name-spaces.js ├── name-uppercase.js ├── npm-defaults.js ├── private-defaults.js ├── repository.js ├── scope-in-config-existing-name.js ├── scope-in-config.js ├── scope.js ├── silent.js └── yes-defaults.js /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | /* This file is automatically added by @npmcli/template-oss. Do not edit. */ 2 | 3 | module.exports = { 4 | extends: ['@commitlint/config-conventional'], 5 | rules: { 6 | 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'deps', 'chore']], 7 | 'header-max-length': [2, 'always', 80], 8 | 'subject-case': [0], 9 | 'body-max-line-length': [0], 10 | 'footer-max-line-length': [0], 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* This file is automatically added by @npmcli/template-oss. Do not edit. */ 2 | 3 | 'use strict' 4 | 5 | const { readdirSync: readdir } = require('fs') 6 | 7 | const localConfigs = readdir(__dirname) 8 | .filter((file) => file.startsWith('.eslintrc.local.')) 9 | .map((file) => `./${file}`) 10 | 11 | module.exports = { 12 | root: true, 13 | ignorePatterns: [ 14 | 'tap-testdir*/', 15 | ], 16 | extends: [ 17 | '@npmcli', 18 | ...localConfigs, 19 | ], 20 | } 21 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | * @npm/cli-team 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: Bug 4 | description: File a bug/issue 5 | title: "[BUG] " 6 | labels: [ Bug, Needs Triage ] 7 | 8 | body: 9 | - type: checkboxes 10 | attributes: 11 | label: Is there an existing issue for this? 12 | description: Please [search here](./issues) to see if an issue already exists for your problem. 13 | options: 14 | - label: I have searched the existing issues 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: Current Behavior 19 | description: A clear & concise description of what you're experiencing. 20 | validations: 21 | required: false 22 | - type: textarea 23 | attributes: 24 | label: Expected Behavior 25 | description: A clear & concise description of what you expected to happen. 26 | validations: 27 | required: false 28 | - type: textarea 29 | attributes: 30 | label: Steps To Reproduce 31 | description: Steps to reproduce the behavior. 32 | value: | 33 | 1. In this environment... 34 | 2. With this config... 35 | 3. Run '...' 36 | 4. See error... 37 | validations: 38 | required: false 39 | - type: textarea 40 | attributes: 41 | label: Environment 42 | description: | 43 | examples: 44 | - **npm**: 7.6.3 45 | - **Node**: 13.14.0 46 | - **OS**: Ubuntu 20.04 47 | - **platform**: Macbook Pro 48 | value: | 49 | - npm: 50 | - Node: 51 | - OS: 52 | - platform: 53 | validations: 54 | required: false 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | blank_issues_enabled: true 4 | -------------------------------------------------------------------------------- /.github/actions/create-check/action.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: 'Create Check' 4 | inputs: 5 | name: 6 | required: true 7 | token: 8 | required: true 9 | sha: 10 | required: true 11 | check-name: 12 | default: '' 13 | outputs: 14 | check-id: 15 | value: ${{ steps.create-check.outputs.check_id }} 16 | runs: 17 | using: "composite" 18 | steps: 19 | - name: Get Workflow Job 20 | uses: actions/github-script@v7 21 | id: workflow 22 | env: 23 | JOB_NAME: "${{ inputs.name }}" 24 | SHA: "${{ inputs.sha }}" 25 | with: 26 | result-encoding: string 27 | script: | 28 | const { repo: { owner, repo}, runId, serverUrl } = context 29 | const { JOB_NAME, SHA } = process.env 30 | 31 | const job = await github.rest.actions.listJobsForWorkflowRun({ 32 | owner, 33 | repo, 34 | run_id: runId, 35 | per_page: 100 36 | }).then(r => r.data.jobs.find(j => j.name.endsWith(JOB_NAME))) 37 | 38 | return [ 39 | `This check is assosciated with ${serverUrl}/${owner}/${repo}/commit/${SHA}.`, 40 | 'Run logs:', 41 | job?.html_url || `could not be found for a job ending with: "${JOB_NAME}"`, 42 | ].join(' ') 43 | - name: Create Check 44 | uses: LouisBrunner/checks-action@v1.6.0 45 | id: create-check 46 | with: 47 | token: ${{ inputs.token }} 48 | sha: ${{ inputs.sha }} 49 | status: in_progress 50 | name: ${{ inputs.check-name || inputs.name }} 51 | output: | 52 | {"summary":"${{ steps.workflow.outputs.result }}"} 53 | -------------------------------------------------------------------------------- /.github/actions/install-latest-npm/action.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: 'Install Latest npm' 4 | description: 'Install the latest version of npm compatible with the Node version' 5 | inputs: 6 | node: 7 | description: 'Current Node version' 8 | required: true 9 | runs: 10 | using: "composite" 11 | steps: 12 | # node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows 13 | - name: Update Windows npm 14 | if: | 15 | runner.os == 'Windows' && ( 16 | startsWith(inputs.node, 'v10.') || 17 | startsWith(inputs.node, 'v12.') || 18 | startsWith(inputs.node, 'v14.') 19 | ) 20 | shell: cmd 21 | run: | 22 | curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz 23 | tar xf npm-7.5.4.tgz 24 | cd package 25 | node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz 26 | cd .. 27 | rmdir /s /q package 28 | - name: Install Latest npm 29 | shell: bash 30 | env: 31 | NODE_VERSION: ${{ inputs.node }} 32 | working-directory: ${{ runner.temp }} 33 | run: | 34 | MATCH="" 35 | SPECS=("latest" "next-10" "next-9" "next-8" "next-7" "next-6") 36 | 37 | echo "node@$NODE_VERSION" 38 | 39 | for SPEC in ${SPECS[@]}; do 40 | ENGINES=$(npm view npm@$SPEC --json | jq -r '.engines.node') 41 | echo "Checking if node@$NODE_VERSION satisfies npm@$SPEC ($ENGINES)" 42 | 43 | if npx semver -r "$ENGINES" "$NODE_VERSION" > /dev/null; then 44 | MATCH=$SPEC 45 | echo "Found compatible version: npm@$MATCH" 46 | break 47 | fi 48 | done 49 | 50 | if [ -z $MATCH ]; then 51 | echo "Could not find a compatible version of npm for node@$NODE_VERSION" 52 | exit 1 53 | fi 54 | 55 | npm i --prefer-online --no-fund --no-audit -g npm@$MATCH 56 | - name: npm Version 57 | shell: bash 58 | run: npm -v 59 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | version: 2 4 | 5 | updates: 6 | - package-ecosystem: npm 7 | directory: / 8 | schedule: 9 | interval: daily 10 | target-branch: "main" 11 | allow: 12 | - dependency-type: direct 13 | versioning-strategy: increase-if-necessary 14 | commit-message: 15 | prefix: deps 16 | prefix-development: chore 17 | labels: 18 | - "Dependencies" 19 | open-pull-requests-limit: 10 20 | -------------------------------------------------------------------------------- /.github/matchers/tap.json: -------------------------------------------------------------------------------- 1 | { 2 | "//@npmcli/template-oss": "This file is automatically added by @npmcli/template-oss. Do not edit.", 3 | "problemMatcher": [ 4 | { 5 | "owner": "tap", 6 | "pattern": [ 7 | { 8 | "regexp": "^\\s*not ok \\d+ - (.*)", 9 | "message": 1 10 | }, 11 | { 12 | "regexp": "^\\s*---" 13 | }, 14 | { 15 | "regexp": "^\\s*at:" 16 | }, 17 | { 18 | "regexp": "^\\s*line:\\s*(\\d+)", 19 | "line": 1 20 | }, 21 | { 22 | "regexp": "^\\s*column:\\s*(\\d+)", 23 | "column": 1 24 | }, 25 | { 26 | "regexp": "^\\s*file:\\s*(.*)", 27 | "file": 1 28 | } 29 | ] 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | repository: 4 | allow_merge_commit: false 5 | allow_rebase_merge: true 6 | allow_squash_merge: true 7 | squash_merge_commit_title: PR_TITLE 8 | squash_merge_commit_message: PR_BODY 9 | delete_branch_on_merge: true 10 | enable_automated_security_fixes: true 11 | enable_vulnerability_alerts: true 12 | 13 | branches: 14 | - name: main 15 | protection: 16 | required_status_checks: null 17 | enforce_admins: true 18 | block_creations: true 19 | required_pull_request_reviews: 20 | required_approving_review_count: 1 21 | require_code_owner_reviews: true 22 | require_last_push_approval: true 23 | dismiss_stale_reviews: true 24 | restrictions: 25 | apps: [] 26 | users: [] 27 | teams: [ "cli-team" ] 28 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: Audit 4 | 5 | on: 6 | workflow_dispatch: 7 | schedule: 8 | # "At 08:00 UTC (01:00 PT) on Monday" https://crontab.guru/#0_8_*_*_1 9 | - cron: "0 8 * * 1" 10 | 11 | jobs: 12 | audit: 13 | name: Audit Dependencies 14 | if: github.repository_owner == 'npm' 15 | runs-on: ubuntu-latest 16 | defaults: 17 | run: 18 | shell: bash 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | - name: Setup Git User 23 | run: | 24 | git config --global user.email "npm-cli+bot@github.com" 25 | git config --global user.name "npm CLI robot" 26 | - name: Setup Node 27 | uses: actions/setup-node@v4 28 | id: node 29 | with: 30 | node-version: 22.x 31 | check-latest: contains('22.x', '.x') 32 | - name: Install Latest npm 33 | uses: ./.github/actions/install-latest-npm 34 | with: 35 | node: ${{ steps.node.outputs.node-version }} 36 | - name: Install Dependencies 37 | run: npm i --ignore-scripts --no-audit --no-fund --package-lock 38 | - name: Run Production Audit 39 | run: npm audit --omit=dev 40 | - name: Run Full Audit 41 | run: npm audit --audit-level=none 42 | -------------------------------------------------------------------------------- /.github/workflows/ci-release.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: CI - Release 4 | 5 | on: 6 | workflow_dispatch: 7 | inputs: 8 | ref: 9 | required: true 10 | type: string 11 | default: main 12 | workflow_call: 13 | inputs: 14 | ref: 15 | required: true 16 | type: string 17 | check-sha: 18 | required: true 19 | type: string 20 | 21 | jobs: 22 | lint-all: 23 | name: Lint All 24 | if: github.repository_owner == 'npm' 25 | runs-on: ubuntu-latest 26 | defaults: 27 | run: 28 | shell: bash 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v4 32 | with: 33 | ref: ${{ inputs.ref }} 34 | - name: Setup Git User 35 | run: | 36 | git config --global user.email "npm-cli+bot@github.com" 37 | git config --global user.name "npm CLI robot" 38 | - name: Create Check 39 | id: create-check 40 | if: ${{ inputs.check-sha }} 41 | uses: ./.github/actions/create-check 42 | with: 43 | name: "Lint All" 44 | token: ${{ secrets.GITHUB_TOKEN }} 45 | sha: ${{ inputs.check-sha }} 46 | - name: Setup Node 47 | uses: actions/setup-node@v4 48 | id: node 49 | with: 50 | node-version: 22.x 51 | check-latest: contains('22.x', '.x') 52 | - name: Install Latest npm 53 | uses: ./.github/actions/install-latest-npm 54 | with: 55 | node: ${{ steps.node.outputs.node-version }} 56 | - name: Install Dependencies 57 | run: npm i --ignore-scripts --no-audit --no-fund 58 | - name: Lint 59 | run: npm run lint --ignore-scripts 60 | - name: Post Lint 61 | run: npm run postlint --ignore-scripts 62 | - name: Conclude Check 63 | uses: LouisBrunner/checks-action@v1.6.0 64 | if: steps.create-check.outputs.check-id && always() 65 | with: 66 | token: ${{ secrets.GITHUB_TOKEN }} 67 | conclusion: ${{ job.status }} 68 | check_id: ${{ steps.create-check.outputs.check-id }} 69 | 70 | test-all: 71 | name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} 72 | if: github.repository_owner == 'npm' 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | platform: 77 | - name: Linux 78 | os: ubuntu-latest 79 | shell: bash 80 | - name: macOS 81 | os: macos-latest 82 | shell: bash 83 | - name: macOS 84 | os: macos-13 85 | shell: bash 86 | - name: Windows 87 | os: windows-latest 88 | shell: cmd 89 | node-version: 90 | - 20.17.0 91 | - 20.x 92 | - 22.9.0 93 | - 22.x 94 | exclude: 95 | - platform: { name: macOS, os: macos-13, shell: bash } 96 | node-version: 20.17.0 97 | - platform: { name: macOS, os: macos-13, shell: bash } 98 | node-version: 20.x 99 | - platform: { name: macOS, os: macos-13, shell: bash } 100 | node-version: 22.9.0 101 | - platform: { name: macOS, os: macos-13, shell: bash } 102 | node-version: 22.x 103 | runs-on: ${{ matrix.platform.os }} 104 | defaults: 105 | run: 106 | shell: ${{ matrix.platform.shell }} 107 | steps: 108 | - name: Checkout 109 | uses: actions/checkout@v4 110 | with: 111 | ref: ${{ inputs.ref }} 112 | - name: Setup Git User 113 | run: | 114 | git config --global user.email "npm-cli+bot@github.com" 115 | git config --global user.name "npm CLI robot" 116 | - name: Create Check 117 | id: create-check 118 | if: ${{ inputs.check-sha }} 119 | uses: ./.github/actions/create-check 120 | with: 121 | name: "Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }}" 122 | token: ${{ secrets.GITHUB_TOKEN }} 123 | sha: ${{ inputs.check-sha }} 124 | - name: Setup Node 125 | uses: actions/setup-node@v4 126 | id: node 127 | with: 128 | node-version: ${{ matrix.node-version }} 129 | check-latest: contains(matrix.node-version, '.x') 130 | - name: Install Latest npm 131 | uses: ./.github/actions/install-latest-npm 132 | with: 133 | node: ${{ steps.node.outputs.node-version }} 134 | - name: Install Dependencies 135 | run: npm i --ignore-scripts --no-audit --no-fund 136 | - name: Add Problem Matcher 137 | run: echo "::add-matcher::.github/matchers/tap.json" 138 | - name: Test 139 | run: npm test --ignore-scripts 140 | - name: Conclude Check 141 | uses: LouisBrunner/checks-action@v1.6.0 142 | if: steps.create-check.outputs.check-id && always() 143 | with: 144 | token: ${{ secrets.GITHUB_TOKEN }} 145 | conclusion: ${{ job.status }} 146 | check_id: ${{ steps.create-check.outputs.check-id }} 147 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: CI 4 | 5 | on: 6 | workflow_dispatch: 7 | pull_request: 8 | push: 9 | branches: 10 | - main 11 | schedule: 12 | # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 13 | - cron: "0 9 * * 1" 14 | 15 | jobs: 16 | lint: 17 | name: Lint 18 | if: github.repository_owner == 'npm' 19 | runs-on: ubuntu-latest 20 | defaults: 21 | run: 22 | shell: bash 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | - name: Setup Git User 27 | run: | 28 | git config --global user.email "npm-cli+bot@github.com" 29 | git config --global user.name "npm CLI robot" 30 | - name: Setup Node 31 | uses: actions/setup-node@v4 32 | id: node 33 | with: 34 | node-version: 22.x 35 | check-latest: contains('22.x', '.x') 36 | - name: Install Latest npm 37 | uses: ./.github/actions/install-latest-npm 38 | with: 39 | node: ${{ steps.node.outputs.node-version }} 40 | - name: Install Dependencies 41 | run: npm i --ignore-scripts --no-audit --no-fund 42 | - name: Lint 43 | run: npm run lint --ignore-scripts 44 | - name: Post Lint 45 | run: npm run postlint --ignore-scripts 46 | 47 | test: 48 | name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} 49 | if: github.repository_owner == 'npm' 50 | strategy: 51 | fail-fast: false 52 | matrix: 53 | platform: 54 | - name: Linux 55 | os: ubuntu-latest 56 | shell: bash 57 | - name: macOS 58 | os: macos-latest 59 | shell: bash 60 | - name: macOS 61 | os: macos-13 62 | shell: bash 63 | - name: Windows 64 | os: windows-latest 65 | shell: cmd 66 | node-version: 67 | - 20.17.0 68 | - 20.x 69 | - 22.9.0 70 | - 22.x 71 | exclude: 72 | - platform: { name: macOS, os: macos-13, shell: bash } 73 | node-version: 20.17.0 74 | - platform: { name: macOS, os: macos-13, shell: bash } 75 | node-version: 20.x 76 | - platform: { name: macOS, os: macos-13, shell: bash } 77 | node-version: 22.9.0 78 | - platform: { name: macOS, os: macos-13, shell: bash } 79 | node-version: 22.x 80 | runs-on: ${{ matrix.platform.os }} 81 | defaults: 82 | run: 83 | shell: ${{ matrix.platform.shell }} 84 | steps: 85 | - name: Checkout 86 | uses: actions/checkout@v4 87 | - name: Setup Git User 88 | run: | 89 | git config --global user.email "npm-cli+bot@github.com" 90 | git config --global user.name "npm CLI robot" 91 | - name: Setup Node 92 | uses: actions/setup-node@v4 93 | id: node 94 | with: 95 | node-version: ${{ matrix.node-version }} 96 | check-latest: contains(matrix.node-version, '.x') 97 | - name: Install Latest npm 98 | uses: ./.github/actions/install-latest-npm 99 | with: 100 | node: ${{ steps.node.outputs.node-version }} 101 | - name: Install Dependencies 102 | run: npm i --ignore-scripts --no-audit --no-fund 103 | - name: Add Problem Matcher 104 | run: echo "::add-matcher::.github/matchers/tap.json" 105 | - name: Test 106 | run: npm test --ignore-scripts 107 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: CodeQL 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | pull_request: 10 | branches: 11 | - main 12 | schedule: 13 | # "At 10:00 UTC (03:00 PT) on Monday" https://crontab.guru/#0_10_*_*_1 14 | - cron: "0 10 * * 1" 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze 19 | runs-on: ubuntu-latest 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | - name: Setup Git User 28 | run: | 29 | git config --global user.email "npm-cli+bot@github.com" 30 | git config --global user.name "npm CLI robot" 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v3 33 | with: 34 | languages: javascript 35 | - name: Perform CodeQL Analysis 36 | uses: github/codeql-action/analyze@v3 37 | -------------------------------------------------------------------------------- /.github/workflows/post-dependabot.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: Post Dependabot 4 | 5 | on: pull_request 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | template-oss: 12 | name: template-oss 13 | if: github.repository_owner == 'npm' && github.actor == 'dependabot[bot]' 14 | runs-on: ubuntu-latest 15 | defaults: 16 | run: 17 | shell: bash 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | with: 22 | ref: ${{ github.event.pull_request.head.ref }} 23 | - name: Setup Git User 24 | run: | 25 | git config --global user.email "npm-cli+bot@github.com" 26 | git config --global user.name "npm CLI robot" 27 | - name: Setup Node 28 | uses: actions/setup-node@v4 29 | id: node 30 | with: 31 | node-version: 22.x 32 | check-latest: contains('22.x', '.x') 33 | - name: Install Latest npm 34 | uses: ./.github/actions/install-latest-npm 35 | with: 36 | node: ${{ steps.node.outputs.node-version }} 37 | - name: Install Dependencies 38 | run: npm i --ignore-scripts --no-audit --no-fund 39 | - name: Fetch Dependabot Metadata 40 | id: metadata 41 | uses: dependabot/fetch-metadata@v1 42 | with: 43 | github-token: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | # Dependabot can update multiple directories so we output which directory 46 | # it is acting on so we can run the command for the correct root or workspace 47 | - name: Get Dependabot Directory 48 | if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') 49 | id: flags 50 | run: | 51 | dependabot_dir="${{ steps.metadata.outputs.directory }}" 52 | if [[ "$dependabot_dir" == "/" || "$dependabot_dir" == "/main" ]]; then 53 | echo "workspace=-iwr" >> $GITHUB_OUTPUT 54 | else 55 | # strip leading slash from directory so it works as a 56 | # a path to the workspace flag 57 | echo "workspace=-w ${dependabot_dir#/}" >> $GITHUB_OUTPUT 58 | fi 59 | 60 | - name: Apply Changes 61 | if: steps.flags.outputs.workspace 62 | id: apply 63 | run: | 64 | npm run template-oss-apply ${{ steps.flags.outputs.workspace }} 65 | if [[ `git status --porcelain` ]]; then 66 | echo "changes=true" >> $GITHUB_OUTPUT 67 | fi 68 | # This only sets the conventional commit prefix. This workflow can't reliably determine 69 | # what the breaking change is though. If a BREAKING CHANGE message is required then 70 | # this PR check will fail and the commit will be amended with stafftools 71 | if [[ "${{ steps.metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then 72 | prefix='feat!' 73 | else 74 | prefix='chore' 75 | fi 76 | echo "message=$prefix: postinstall for dependabot template-oss PR" >> $GITHUB_OUTPUT 77 | 78 | # This step will fail if template-oss has made any workflow updates. It is impossible 79 | # for a workflow to update other workflows. In the case it does fail, we continue 80 | # and then try to apply only a portion of the changes in the next step 81 | - name: Push All Changes 82 | if: steps.apply.outputs.changes 83 | id: push 84 | continue-on-error: true 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | run: | 88 | git commit -am "${{ steps.apply.outputs.message }}" 89 | git push 90 | 91 | # If the previous step failed, then reset the commit and remove any workflow changes 92 | # and attempt to commit and push again. This is helpful because we will have a commit 93 | # with the correct prefix that we can then --amend with @npmcli/stafftools later. 94 | - name: Push All Changes Except Workflows 95 | if: steps.apply.outputs.changes && steps.push.outcome == 'failure' 96 | env: 97 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 98 | run: | 99 | git reset HEAD~ 100 | git checkout HEAD -- .github/workflows/ 101 | git clean -fd .github/workflows/ 102 | git commit -am "${{ steps.apply.outputs.message }}" 103 | git push 104 | 105 | # Check if all the necessary template-oss changes were applied. Since we continued 106 | # on errors in one of the previous steps, this check will fail if our follow up 107 | # only applied a portion of the changes and we need to followup manually. 108 | # 109 | # Note that this used to run `lint` and `postlint` but that will fail this action 110 | # if we've also shipped any linting changes separate from template-oss. We do 111 | # linting in another action, so we want to fail this one only if there are 112 | # template-oss changes that could not be applied. 113 | - name: Check Changes 114 | if: steps.apply.outputs.changes 115 | run: | 116 | npm exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check 117 | 118 | - name: Fail on Breaking Change 119 | if: steps.apply.outputs.changes && startsWith(steps.apply.outputs.message, 'feat!') 120 | run: | 121 | echo "This PR has a breaking change. Run 'npx -p @npmcli/stafftools gh template-oss-fix'" 122 | echo "for more information on how to fix this with a BREAKING CHANGE footer." 123 | exit 1 124 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: Pull Request 4 | 5 | on: 6 | pull_request: 7 | types: 8 | - opened 9 | - reopened 10 | - edited 11 | - synchronize 12 | 13 | jobs: 14 | commitlint: 15 | name: Lint Commits 16 | if: github.repository_owner == 'npm' 17 | runs-on: ubuntu-latest 18 | defaults: 19 | run: 20 | shell: bash 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | - name: Setup Git User 27 | run: | 28 | git config --global user.email "npm-cli+bot@github.com" 29 | git config --global user.name "npm CLI robot" 30 | - name: Setup Node 31 | uses: actions/setup-node@v4 32 | id: node 33 | with: 34 | node-version: 22.x 35 | check-latest: contains('22.x', '.x') 36 | - name: Install Latest npm 37 | uses: ./.github/actions/install-latest-npm 38 | with: 39 | node: ${{ steps.node.outputs.node-version }} 40 | - name: Install Dependencies 41 | run: npm i --ignore-scripts --no-audit --no-fund 42 | - name: Run Commitlint on Commits 43 | id: commit 44 | continue-on-error: true 45 | run: npx --offline commitlint -V --from 'origin/${{ github.base_ref }}' --to ${{ github.event.pull_request.head.sha }} 46 | - name: Run Commitlint on PR Title 47 | if: steps.commit.outcome == 'failure' 48 | env: 49 | PR_TITLE: ${{ github.event.pull_request.title }} 50 | run: echo "$PR_TITLE" | npx --offline commitlint -V 51 | -------------------------------------------------------------------------------- /.github/workflows/release-integration.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: Release Integration 4 | 5 | on: 6 | workflow_dispatch: 7 | inputs: 8 | releases: 9 | required: true 10 | type: string 11 | description: 'A json array of releases. Required fields: publish: tagName, publishTag. publish check: pkgName, version' 12 | workflow_call: 13 | inputs: 14 | releases: 15 | required: true 16 | type: string 17 | description: 'A json array of releases. Required fields: publish: tagName, publishTag. publish check: pkgName, version' 18 | secrets: 19 | PUBLISH_TOKEN: 20 | required: true 21 | 22 | jobs: 23 | publish: 24 | name: Publish 25 | runs-on: ubuntu-latest 26 | defaults: 27 | run: 28 | shell: bash 29 | permissions: 30 | id-token: write 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | with: 35 | ref: ${{ fromJSON(inputs.releases)[0].tagName }} 36 | - name: Setup Git User 37 | run: | 38 | git config --global user.email "npm-cli+bot@github.com" 39 | git config --global user.name "npm CLI robot" 40 | - name: Setup Node 41 | uses: actions/setup-node@v4 42 | id: node 43 | with: 44 | node-version: 22.x 45 | check-latest: contains('22.x', '.x') 46 | - name: Install Latest npm 47 | uses: ./.github/actions/install-latest-npm 48 | with: 49 | node: ${{ steps.node.outputs.node-version }} 50 | - name: Install Dependencies 51 | run: npm i --ignore-scripts --no-audit --no-fund 52 | - name: Set npm authToken 53 | run: npm config set '//registry.npmjs.org/:_authToken'=\${PUBLISH_TOKEN} 54 | - name: Publish 55 | env: 56 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 57 | RELEASES: ${{ inputs.releases }} 58 | run: | 59 | EXIT_CODE=0 60 | 61 | for release in $(echo $RELEASES | jq -r '.[] | @base64'); do 62 | PUBLISH_TAG=$(echo "$release" | base64 --decode | jq -r .publishTag) 63 | npm publish --provenance --tag="$PUBLISH_TAG" 64 | STATUS=$? 65 | if [[ "$STATUS" -eq 1 ]]; then 66 | EXIT_CODE=$STATUS 67 | fi 68 | done 69 | 70 | exit $EXIT_CODE 71 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | name: Release 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | 10 | permissions: 11 | contents: write 12 | pull-requests: write 13 | checks: write 14 | 15 | jobs: 16 | release: 17 | outputs: 18 | pr: ${{ steps.release.outputs.pr }} 19 | pr-branch: ${{ steps.release.outputs.pr-branch }} 20 | pr-number: ${{ steps.release.outputs.pr-number }} 21 | pr-sha: ${{ steps.release.outputs.pr-sha }} 22 | releases: ${{ steps.release.outputs.releases }} 23 | comment-id: ${{ steps.create-comment.outputs.comment-id || steps.update-comment.outputs.comment-id }} 24 | check-id: ${{ steps.create-check.outputs.check-id }} 25 | name: Release 26 | if: github.repository_owner == 'npm' 27 | runs-on: ubuntu-latest 28 | defaults: 29 | run: 30 | shell: bash 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | - name: Setup Git User 35 | run: | 36 | git config --global user.email "npm-cli+bot@github.com" 37 | git config --global user.name "npm CLI robot" 38 | - name: Setup Node 39 | uses: actions/setup-node@v4 40 | id: node 41 | with: 42 | node-version: 22.x 43 | check-latest: contains('22.x', '.x') 44 | - name: Install Latest npm 45 | uses: ./.github/actions/install-latest-npm 46 | with: 47 | node: ${{ steps.node.outputs.node-version }} 48 | - name: Install Dependencies 49 | run: npm i --ignore-scripts --no-audit --no-fund 50 | - name: Release Please 51 | id: release 52 | env: 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | run: npx --offline template-oss-release-please --branch="${{ github.ref_name }}" --backport="" --defaultTag="latest" 55 | - name: Create Release Manager Comment Text 56 | if: steps.release.outputs.pr-number 57 | uses: actions/github-script@v7 58 | id: comment-text 59 | with: 60 | result-encoding: string 61 | script: | 62 | const { runId, repo: { owner, repo } } = context 63 | const { data: workflow } = await github.rest.actions.getWorkflowRun({ owner, repo, run_id: runId }) 64 | return['## Release Manager', `Release workflow run: ${workflow.html_url}`].join('\n\n') 65 | - name: Find Release Manager Comment 66 | uses: peter-evans/find-comment@v2 67 | if: steps.release.outputs.pr-number 68 | id: found-comment 69 | with: 70 | issue-number: ${{ steps.release.outputs.pr-number }} 71 | comment-author: 'github-actions[bot]' 72 | body-includes: '## Release Manager' 73 | - name: Create Release Manager Comment 74 | id: create-comment 75 | if: steps.release.outputs.pr-number && !steps.found-comment.outputs.comment-id 76 | uses: peter-evans/create-or-update-comment@v3 77 | with: 78 | issue-number: ${{ steps.release.outputs.pr-number }} 79 | body: ${{ steps.comment-text.outputs.result }} 80 | - name: Update Release Manager Comment 81 | id: update-comment 82 | if: steps.release.outputs.pr-number && steps.found-comment.outputs.comment-id 83 | uses: peter-evans/create-or-update-comment@v3 84 | with: 85 | comment-id: ${{ steps.found-comment.outputs.comment-id }} 86 | body: ${{ steps.comment-text.outputs.result }} 87 | edit-mode: 'replace' 88 | - name: Create Check 89 | id: create-check 90 | uses: ./.github/actions/create-check 91 | if: steps.release.outputs.pr-sha 92 | with: 93 | name: "Release" 94 | token: ${{ secrets.GITHUB_TOKEN }} 95 | sha: ${{ steps.release.outputs.pr-sha }} 96 | 97 | update: 98 | needs: release 99 | outputs: 100 | sha: ${{ steps.commit.outputs.sha }} 101 | check-id: ${{ steps.create-check.outputs.check-id }} 102 | name: Update - Release 103 | if: github.repository_owner == 'npm' && needs.release.outputs.pr 104 | runs-on: ubuntu-latest 105 | defaults: 106 | run: 107 | shell: bash 108 | steps: 109 | - name: Checkout 110 | uses: actions/checkout@v4 111 | with: 112 | fetch-depth: 0 113 | ref: ${{ needs.release.outputs.pr-branch }} 114 | - name: Setup Git User 115 | run: | 116 | git config --global user.email "npm-cli+bot@github.com" 117 | git config --global user.name "npm CLI robot" 118 | - name: Setup Node 119 | uses: actions/setup-node@v4 120 | id: node 121 | with: 122 | node-version: 22.x 123 | check-latest: contains('22.x', '.x') 124 | - name: Install Latest npm 125 | uses: ./.github/actions/install-latest-npm 126 | with: 127 | node: ${{ steps.node.outputs.node-version }} 128 | - name: Install Dependencies 129 | run: npm i --ignore-scripts --no-audit --no-fund 130 | - name: Create Release Manager Checklist Text 131 | id: comment-text 132 | env: 133 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 134 | run: npm exec --offline -- template-oss-release-manager --pr="${{ needs.release.outputs.pr-number }}" --backport="" --defaultTag="latest" --publish 135 | - name: Append Release Manager Comment 136 | uses: peter-evans/create-or-update-comment@v3 137 | with: 138 | comment-id: ${{ needs.release.outputs.comment-id }} 139 | body: ${{ steps.comment-text.outputs.result }} 140 | edit-mode: 'append' 141 | - name: Run Post Pull Request Actions 142 | env: 143 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 144 | run: npm run rp-pull-request --ignore-scripts --if-present -- --pr="${{ needs.release.outputs.pr-number }}" --commentId="${{ needs.release.outputs.comment-id }}" 145 | - name: Commit 146 | id: commit 147 | env: 148 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 149 | run: | 150 | git commit --all --amend --no-edit || true 151 | git push --force-with-lease 152 | echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT 153 | - name: Create Check 154 | id: create-check 155 | uses: ./.github/actions/create-check 156 | with: 157 | name: "Update - Release" 158 | check-name: "Release" 159 | token: ${{ secrets.GITHUB_TOKEN }} 160 | sha: ${{ steps.commit.outputs.sha }} 161 | - name: Conclude Check 162 | uses: LouisBrunner/checks-action@v1.6.0 163 | with: 164 | token: ${{ secrets.GITHUB_TOKEN }} 165 | conclusion: ${{ job.status }} 166 | check_id: ${{ needs.release.outputs.check-id }} 167 | 168 | ci: 169 | name: CI - Release 170 | needs: [ release, update ] 171 | if: needs.release.outputs.pr 172 | uses: ./.github/workflows/ci-release.yml 173 | with: 174 | ref: ${{ needs.release.outputs.pr-branch }} 175 | check-sha: ${{ needs.update.outputs.sha }} 176 | 177 | post-ci: 178 | needs: [ release, update, ci ] 179 | name: Post CI - Release 180 | if: github.repository_owner == 'npm' && needs.release.outputs.pr && always() 181 | runs-on: ubuntu-latest 182 | defaults: 183 | run: 184 | shell: bash 185 | steps: 186 | - name: Get CI Conclusion 187 | id: conclusion 188 | run: | 189 | result="" 190 | if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then 191 | result="failure" 192 | elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then 193 | result="cancelled" 194 | else 195 | result="success" 196 | fi 197 | echo "result=$result" >> $GITHUB_OUTPUT 198 | - name: Conclude Check 199 | uses: LouisBrunner/checks-action@v1.6.0 200 | with: 201 | token: ${{ secrets.GITHUB_TOKEN }} 202 | conclusion: ${{ steps.conclusion.outputs.result }} 203 | check_id: ${{ needs.update.outputs.check-id }} 204 | 205 | post-release: 206 | needs: release 207 | outputs: 208 | comment-id: ${{ steps.create-comment.outputs.comment-id }} 209 | name: Post Release - Release 210 | if: github.repository_owner == 'npm' && needs.release.outputs.releases 211 | runs-on: ubuntu-latest 212 | defaults: 213 | run: 214 | shell: bash 215 | steps: 216 | - name: Create Release PR Comment Text 217 | id: comment-text 218 | uses: actions/github-script@v7 219 | env: 220 | RELEASES: ${{ needs.release.outputs.releases }} 221 | with: 222 | result-encoding: string 223 | script: | 224 | const releases = JSON.parse(process.env.RELEASES) 225 | const { runId, repo: { owner, repo } } = context 226 | const issue_number = releases[0].prNumber 227 | const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${runId}` 228 | 229 | return [ 230 | '## Release Workflow\n', 231 | ...releases.map(r => `- \`${r.pkgName}@${r.version}\` ${r.url}`), 232 | `- Workflow run: :arrows_counterclockwise: ${runUrl}`, 233 | ].join('\n') 234 | - name: Create Release PR Comment 235 | id: create-comment 236 | uses: peter-evans/create-or-update-comment@v3 237 | with: 238 | issue-number: ${{ fromJSON(needs.release.outputs.releases)[0].prNumber }} 239 | body: ${{ steps.comment-text.outputs.result }} 240 | 241 | release-integration: 242 | needs: release 243 | name: Release Integration 244 | if: needs.release.outputs.releases 245 | uses: ./.github/workflows/release-integration.yml 246 | permissions: 247 | id-token: write 248 | secrets: 249 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 250 | with: 251 | releases: ${{ needs.release.outputs.releases }} 252 | 253 | post-release-integration: 254 | needs: [ release, release-integration, post-release ] 255 | name: Post Release Integration - Release 256 | if: github.repository_owner == 'npm' && needs.release.outputs.releases && always() 257 | runs-on: ubuntu-latest 258 | defaults: 259 | run: 260 | shell: bash 261 | steps: 262 | - name: Get Post Release Conclusion 263 | id: conclusion 264 | run: | 265 | if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then 266 | result="x" 267 | elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then 268 | result="heavy_multiplication_x" 269 | else 270 | result="white_check_mark" 271 | fi 272 | echo "result=$result" >> $GITHUB_OUTPUT 273 | - name: Find Release PR Comment 274 | uses: peter-evans/find-comment@v2 275 | id: found-comment 276 | with: 277 | issue-number: ${{ fromJSON(needs.release.outputs.releases)[0].prNumber }} 278 | comment-author: 'github-actions[bot]' 279 | body-includes: '## Release Workflow' 280 | - name: Create Release PR Comment Text 281 | id: comment-text 282 | if: steps.found-comment.outputs.comment-id 283 | uses: actions/github-script@v7 284 | env: 285 | RESULT: ${{ steps.conclusion.outputs.result }} 286 | BODY: ${{ steps.found-comment.outputs.comment-body }} 287 | with: 288 | result-encoding: string 289 | script: | 290 | const { RESULT, BODY } = process.env 291 | const body = [BODY.replace(/(Workflow run: :)[a-z_]+(:)/, `$1${RESULT}$2`)] 292 | if (RESULT !== 'white_check_mark') { 293 | body.push(':rotating_light::rotating_light::rotating_light:') 294 | body.push([ 295 | '@npm/cli-team: The post-release workflow failed for this release.', 296 | 'Manual steps may need to be taken after examining the workflow output.' 297 | ].join(' ')) 298 | body.push(':rotating_light::rotating_light::rotating_light:') 299 | } 300 | return body.join('\n\n').trim() 301 | - name: Update Release PR Comment 302 | if: steps.comment-text.outputs.result 303 | uses: peter-evans/create-or-update-comment@v3 304 | with: 305 | comment-id: ${{ steps.found-comment.outputs.comment-id }} 306 | body: ${{ steps.comment-text.outputs.result }} 307 | edit-mode: 'replace' 308 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | # ignore everything in the root 4 | /* 5 | 6 | !**/.gitignore 7 | !/.commitlintrc.js 8 | !/.eslintrc.js 9 | !/.eslintrc.local.* 10 | !/.git-blame-ignore-revs 11 | !/.github/ 12 | !/.gitignore 13 | !/.npmrc 14 | !/.prettierignore 15 | !/.prettierrc.js 16 | !/.release-please-manifest.json 17 | !/bin/ 18 | !/CHANGELOG* 19 | !/CODE_OF_CONDUCT.md 20 | !/CONTRIBUTING.md 21 | !/docs/ 22 | !/lib/ 23 | !/LICENSE* 24 | !/map.js 25 | !/package.json 26 | !/README* 27 | !/release-please-config.json 28 | !/scripts/ 29 | !/SECURITY.md 30 | !/tap-snapshots/ 31 | !/test/ 32 | !/tsconfig.json 33 | tap-testdir*/ 34 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ; This file is automatically added by @npmcli/template-oss. Do not edit. 2 | 3 | package-lock=false 4 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "8.2.1" 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [8.2.1](https://github.com/npm/init-package-json/compare/v8.2.0...v8.2.1) (2025-05-14) 4 | ### Bug Fixes 5 | * [`d2da53b`](https://github.com/npm/init-package-json/commit/d2da53b5ccff49d008cb138db5c56bcb02ca7b77) [#330](https://github.com/npm/init-package-json/pull/330) private option uses the real config to determine default (#330) (@owlstronaut) 6 | 7 | ## [8.2.0](https://github.com/npm/init-package-json/compare/v8.1.1...v8.2.0) (2025-05-05) 8 | ### Features 9 | * [`8f6d95d`](https://github.com/npm/init-package-json/commit/8f6d95d539a0e5334a2452869ab39738d50c2652) [#329](https://github.com/npm/init-package-json/pull/329) add new test packages (#329) (@wraithgar) 10 | ### Bug Fixes 11 | * [`23c5eb9`](https://github.com/npm/init-package-json/commit/23c5eb9e5948f5888844c351a57f3d7f500b342f) [#327](https://github.com/npm/init-package-json/pull/327) Use the private value as long as it isn't undefined (#327) (@owlstronaut) 12 | 13 | ## [8.1.1](https://github.com/npm/init-package-json/compare/v8.1.0...v8.1.1) (2025-04-23) 14 | ### Bug Fixes 15 | * [`52b3766`](https://github.com/npm/init-package-json/commit/52b37660aa87e67261a6e63ab3b6f6d32c358a99) [#324](https://github.com/npm/init-package-json/pull/324) make private only effective when set to true, handle existing packages (#324) (@owlstronaut) 16 | 17 | ## [8.1.0](https://github.com/npm/init-package-json/compare/v8.0.0...v8.1.0) (2025-04-23) 18 | ### Features 19 | * [`78b2cd0`](https://github.com/npm/init-package-json/commit/78b2cd07d692004b41daf140662f15b8f9c7d49c) [#322](https://github.com/npm/init-package-json/pull/322) adds init-private option to config (#322) (@owlstronaut) 20 | ### Chores 21 | * [`0578b8b`](https://github.com/npm/init-package-json/commit/0578b8ba703b92204e312c73d8aef9b93ef25e6a) [#320](https://github.com/npm/init-package-json/pull/320) bump @npmcli/config from 9.0.0 to 10.0.0 (#320) (@dependabot[bot]) 22 | 23 | ## [8.0.0](https://github.com/npm/init-package-json/compare/v7.0.2...v8.0.0) (2024-12-02) 24 | ### ⚠️ BREAKING CHANGES 25 | * this module is now compatible with the following node versions: ^20.17.0 || >=22.9.0 26 | * adds a new `type` prompt and changes the sort order of created packages 27 | ### Features 28 | * [`5eeea50`](https://github.com/npm/init-package-json/commit/5eeea50f70412968d8e16b390da43cab5de02954) [#313](https://github.com/npm/init-package-json/pull/313) adds type, sorting (#313) (@reggi) 29 | ### Bug Fixes 30 | * [`f4c1430`](https://github.com/npm/init-package-json/commit/f4c1430696ecc00db3bd0864b1682f94fe3ee6a0) update node engines to ^20.17.0 || >=22.9.0 (#318) (@wraithgar) 31 | ### Chores 32 | * [`47339ef`](https://github.com/npm/init-package-json/commit/47339efdc51cdadd36d0c6abeff178f97acbfa10) [#311](https://github.com/npm/init-package-json/pull/311) bump @npmcli/config from 8.3.4 to 9.0.0 (#311) (@dependabot[bot]) 33 | * [`2ccbf30`](https://github.com/npm/init-package-json/commit/2ccbf30b19f7ed95b161a7ff85de40cd3d5d150a) [#310](https://github.com/npm/init-package-json/pull/310) bump @npmcli/template-oss from 4.23.3 to 4.23.4 (#310) (@dependabot[bot], @npm-cli-bot) 34 | 35 | ## [7.0.2](https://github.com/npm/init-package-json/compare/v7.0.1...v7.0.2) (2024-12-02) 36 | ### Bug Fixes 37 | * [`c96ad4a`](https://github.com/npm/init-package-json/commit/c96ad4a74a03a33875a9f3472ac320f5a1177dc3) [#315](https://github.com/npm/init-package-json/pull/315) default git repository value if exist (#315) (@milaninfy) 38 | 39 | ## [7.0.1](https://github.com/npm/init-package-json/compare/v7.0.0...v7.0.1) (2024-10-02) 40 | ### Dependencies 41 | * [`90305f1`](https://github.com/npm/init-package-json/commit/90305f11cfa78b8e40f990da46eaeda852d2454b) [#308](https://github.com/npm/init-package-json/pull/308) bump `@npmcli/package-json@6.0.0` 42 | 43 | ## [7.0.0](https://github.com/npm/init-package-json/compare/v6.0.3...v7.0.0) (2024-09-26) 44 | ### ⚠️ BREAKING CHANGES 45 | * `init-package-json` now supports node `^18.17.0 || >=20.5.0` 46 | ### Bug Fixes 47 | * [`2c78533`](https://github.com/npm/init-package-json/commit/2c785335c783231adaeb5d00f5323c7f24fdc0ba) [#305](https://github.com/npm/init-package-json/pull/305) align to npm 10 node engine range (@reggi) 48 | ### Dependencies 49 | * [`732dc0d`](https://github.com/npm/init-package-json/commit/732dc0d4d73bf9278e2ffe5ee672f1853a76bfd2) [#305](https://github.com/npm/init-package-json/pull/305) `validate-npm-package-name@6.0.0` 50 | * [`bdb71d9`](https://github.com/npm/init-package-json/commit/bdb71d9bb45806c3550fefa6688438a38f3b7b18) [#305](https://github.com/npm/init-package-json/pull/305) `read@4.0.0` 51 | * [`2a6ebd2`](https://github.com/npm/init-package-json/commit/2a6ebd2ec94bb0ade18c8b22e9f4e869b0460b8b) [#305](https://github.com/npm/init-package-json/pull/305) `promzard@2.0.0` 52 | * [`45bb12a`](https://github.com/npm/init-package-json/commit/45bb12a76030e8c246e9f6d22a120c50bb52774a) [#305](https://github.com/npm/init-package-json/pull/305) `npm-package-arg@12.0.0` 53 | ### Chores 54 | * [`c8deea5`](https://github.com/npm/init-package-json/commit/c8deea51d429511976cdae5e296f24559068aacd) [#305](https://github.com/npm/init-package-json/pull/305) run template-oss-apply (@reggi) 55 | * [`e61c6c7`](https://github.com/npm/init-package-json/commit/e61c6c7f998918098342eecd79c426b56fc992bf) [#299](https://github.com/npm/init-package-json/pull/299) bump @npmcli/eslint-config from 4.0.5 to 5.0.0 (@dependabot[bot]) 56 | * [`c3f2bfe`](https://github.com/npm/init-package-json/commit/c3f2bfef507b9d4413d59d399b827c6e0aa7e44f) [#300](https://github.com/npm/init-package-json/pull/300) postinstall for dependabot template-oss PR (@hashtagchris) 57 | * [`9569c5d`](https://github.com/npm/init-package-json/commit/9569c5d9bc26a9e3f75ef47c7ef17ae638f00fc9) [#300](https://github.com/npm/init-package-json/pull/300) bump @npmcli/template-oss from 4.23.1 to 4.23.3 (@dependabot[bot]) 58 | 59 | ## [6.0.3](https://github.com/npm/init-package-json/compare/v6.0.2...v6.0.3) (2024-05-04) 60 | 61 | ### Bug Fixes 62 | 63 | * [`3d50080`](https://github.com/npm/init-package-json/commit/3d500804f644efa8743f16bd4d101f749c3d433b) [#284](https://github.com/npm/init-package-json/pull/284) linting: no-console (@lukekarrys) 64 | 65 | ### Chores 66 | 67 | * [`c089e8c`](https://github.com/npm/init-package-json/commit/c089e8cfa73347b736c7ae238cec0ec0de5d3056) [#284](https://github.com/npm/init-package-json/pull/284) increase tap timeout (@lukekarrys) 68 | * [`d9deb25`](https://github.com/npm/init-package-json/commit/d9deb25ac3628763ab31c3f9f5fcbc961e1d808a) [#284](https://github.com/npm/init-package-json/pull/284) bump @npmcli/template-oss to 4.22.0 (@lukekarrys) 69 | * [`5b599d7`](https://github.com/npm/init-package-json/commit/5b599d701c45ec2ac0c2c208ddf1571296a437ee) [#284](https://github.com/npm/init-package-json/pull/284) postinstall for dependabot template-oss PR (@lukekarrys) 70 | * [`2421ced`](https://github.com/npm/init-package-json/commit/2421ced93d851b93239da66703855a4320ee9769) [#282](https://github.com/npm/init-package-json/pull/282) bump @npmcli/template-oss from 4.21.3 to 4.21.4 (@dependabot[bot]) 71 | 72 | ## [6.0.2](https://github.com/npm/init-package-json/compare/v6.0.1...v6.0.2) (2024-03-01) 73 | 74 | ### Dependencies 75 | 76 | * [`4e2383e`](https://github.com/npm/init-package-json/commit/4e2383e5bb6648a6f3511fd5e6d788f0a260412b) [#275](https://github.com/npm/init-package-json/pull/275) bump @npmcli/package-json from 4.0.1 to 5.0.0 (#275) (@dependabot[bot]) 77 | 78 | ## [6.0.1](https://github.com/npm/init-package-json/compare/v6.0.0...v6.0.1) (2024-02-29) 79 | 80 | ### Bug Fixes 81 | 82 | * [`4eca245`](https://github.com/npm/init-package-json/commit/4eca245b0bb4576b9174efe4c1fbd5f3ddf68b73) [#263](https://github.com/npm/init-package-json/pull/263) move to @npmcli/package-json (@wraithgar) 83 | 84 | ### Dependencies 85 | 86 | * [`85b4452`](https://github.com/npm/init-package-json/commit/85b4452f8f3c2060ff24ef8b8ff8a72dcae5a1ee) [#274](https://github.com/npm/init-package-json/pull/274) bump read from 2.1.0 to 3.0.1 (#274) 87 | * [`16f1fcc`](https://github.com/npm/init-package-json/commit/16f1fcc94a8b5ac3f145ec4f2e6f5a340f46c54c) [#263](https://github.com/npm/init-package-json/pull/263) remove read-package-json 88 | * [`5c0da7f`](https://github.com/npm/init-package-json/commit/5c0da7f5d83c78d7b688b45f236daedb4a083e38) [#263](https://github.com/npm/init-package-json/pull/263) add new dependency `@npmcli/package-json@4.0.1` 89 | 90 | ### Chores 91 | 92 | * [`0a12bd7`](https://github.com/npm/init-package-json/commit/0a12bd77e8c1206f6427ecca6d46fb20357b1b70) [#273](https://github.com/npm/init-package-json/pull/273) bump @npmcli/config from 7.2.0 to 8.2.0 (#273) (@dependabot[bot]) 93 | * [`b216462`](https://github.com/npm/init-package-json/commit/b216462566c6a0ab627905a94d1c3ff21fc1121e) [#267](https://github.com/npm/init-package-json/pull/267) postinstall for dependabot template-oss PR (@lukekarrys) 94 | * [`36addd8`](https://github.com/npm/init-package-json/commit/36addd83b459288dae6330bb0493572f1c676944) [#267](https://github.com/npm/init-package-json/pull/267) bump @npmcli/template-oss from 4.21.1 to 4.21.3 (@dependabot[bot]) 95 | * [`38ee762`](https://github.com/npm/init-package-json/commit/38ee762cc43577d25b512c1a7b185a17fd9c9582) [#261](https://github.com/npm/init-package-json/pull/261) postinstall for dependabot template-oss PR (@lukekarrys) 96 | * [`642e170`](https://github.com/npm/init-package-json/commit/642e170a7060969c479005e47e7017c58f1691d7) [#261](https://github.com/npm/init-package-json/pull/261) bump @npmcli/template-oss from 4.19.0 to 4.21.1 (@dependabot[bot]) 97 | * [`4a9b5f1`](https://github.com/npm/init-package-json/commit/4a9b5f1832bd2709e6e432f019f1a964b7159910) [#239](https://github.com/npm/init-package-json/pull/239) postinstall for dependabot template-oss PR (@lukekarrys) 98 | * [`0920582`](https://github.com/npm/init-package-json/commit/0920582b941e39a71bf3b89f3abe28d6533779a9) [#239](https://github.com/npm/init-package-json/pull/239) bump @npmcli/template-oss from 4.18.1 to 4.19.0 (@dependabot[bot]) 99 | * [`9e08db3`](https://github.com/npm/init-package-json/commit/9e08db33cd8705c0e1b1c0a44a4e000d8ffa4f94) [#238](https://github.com/npm/init-package-json/pull/238) postinstall for dependabot template-oss PR (@lukekarrys) 100 | * [`4a274d1`](https://github.com/npm/init-package-json/commit/4a274d1b17be42a091b39672301b9e7b08e81395) [#238](https://github.com/npm/init-package-json/pull/238) bump @npmcli/template-oss from 4.18.0 to 4.18.1 (@dependabot[bot]) 101 | 102 | ## [6.0.0](https://github.com/npm/init-package-json/compare/v5.0.0...v6.0.0) (2023-08-15) 103 | 104 | ### ⚠️ BREAKING CHANGES 105 | 106 | * support for node 14 has been removed 107 | 108 | ### Bug Fixes 109 | 110 | * [`97b1efe`](https://github.com/npm/init-package-json/commit/97b1efeccb6eac3d0669fcd5703ade57ec7fd148) [#235](https://github.com/npm/init-package-json/pull/235) drop node14 support (@lukekarrys) 111 | 112 | ### Dependencies 113 | 114 | * [`9eccb04`](https://github.com/npm/init-package-json/commit/9eccb043c2993371013749a92702b6e4fcdd033d) [#233](https://github.com/npm/init-package-json/pull/233) bump read-package-json from 6.0.4 to 7.0.0 115 | * [`3024040`](https://github.com/npm/init-package-json/commit/3024040dec8c5f0215f9dea8652a28669e9d1c9f) [#234](https://github.com/npm/init-package-json/pull/234) bump npm-package-arg from 10.1.0 to 11.0.0 116 | 117 | ## [5.0.0](https://github.com/npm/init-package-json/compare/v4.0.1...v5.0.0) (2023-02-06) 118 | 119 | ### ⚠️ BREAKING CHANGES 120 | 121 | * this module is now Promise only and no longer accepts a callback parameter 122 | 123 | ### Features 124 | 125 | * [`8b919b7`](https://github.com/npm/init-package-json/commit/8b919b74149af92f4cad76c96080a254a72b7018) refactor (@lukekarrys) 126 | 127 | ## [4.0.1](https://github.com/npm/init-package-json/compare/v4.0.0...v4.0.1) (2022-10-18) 128 | 129 | ### Dependencies 130 | 131 | * [`4dea768`](https://github.com/npm/init-package-json/commit/4dea7685efa3a596eb04d2d4de21902efb0f6c84) [#172](https://github.com/npm/init-package-json/pull/172) bump npm-package-arg from 9.1.2 to 10.0.0 132 | 133 | ## [4.0.0](https://github.com/npm/init-package-json/compare/v3.0.2...v4.0.0) (2022-10-14) 134 | 135 | ### ⚠️ BREAKING CHANGES 136 | 137 | * `init-package-json` is now compatible with the following semver range for node: `^14.17.0 || ^16.13.0 || >=18.0.0` 138 | 139 | ### Features 140 | 141 | * [`e8ea83a`](https://github.com/npm/init-package-json/commit/e8ea83a9546678c63b8f4d842e0819fced2f7513) [#159](https://github.com/npm/init-package-json/pull/159) postinstall for dependabot template-oss PR (@lukekarrys) 142 | 143 | ### Dependencies 144 | 145 | * [`b869b31`](https://github.com/npm/init-package-json/commit/b869b31550beb4a66f72e0232aee2b4e0225a282) [#170](https://github.com/npm/init-package-json/pull/170) bump read-package-json from 5.0.2 to 6.0.0 (#170) 146 | * [`d342821`](https://github.com/npm/init-package-json/commit/d342821532d3066b2db6f681e922131cd5943b01) [#168](https://github.com/npm/init-package-json/pull/168) bump validate-npm-package-name from 4.0.0 to 5.0.0 (#168) 147 | 148 | ### [3.0.2](https://github.com/npm/init-package-json/compare/v3.0.1...v3.0.2) (2022-03-29) 149 | 150 | 151 | ### Dependencies 152 | 153 | * bump validate-npm-package-name from 3.0.0 to 4.0.0 ([#144](https://github.com/npm/init-package-json/issues/144)) ([fa7574a](https://github.com/npm/init-package-json/commit/fa7574adb3672c8c7b537bf960c7860900828ecb)) 154 | * update npm-package-arg requirement from ^9.0.0 to ^9.0.1 ([#136](https://github.com/npm/init-package-json/issues/136)) ([b1ec548](https://github.com/npm/init-package-json/commit/b1ec548592760fd95b6d60f98e61abe4fe84f09f)) 155 | 156 | ### [3.0.1](https://www.github.com/npm/init-package-json/compare/v3.0.0...v3.0.1) (2022-03-15) 157 | 158 | 159 | ### Dependencies 160 | 161 | * bump read-package-json from 4.1.2 to 5.0.0 ([#134](https://www.github.com/npm/init-package-json/issues/134)) ([3b7a109](https://www.github.com/npm/init-package-json/commit/3b7a1099ee0241e8dc1f0ff95eca999a699699fc)) 162 | 163 | ## [3.0.0](https://www.github.com/npm/init-package-json/compare/v2.0.5...v3.0.0) (2022-02-16) 164 | 165 | 166 | ### ⚠ BREAKING CHANGES 167 | 168 | * this drops support for node10 and non-LTS versions of node12 and node14 169 | 170 | ### Dependencies 171 | 172 | * @npmcli/template-oss@2.7.1 ([257ba39](https://www.github.com/npm/init-package-json/commit/257ba391909a7220da964128836b40b14728fab3)) 173 | * npm-package-arg@9.0.0, @npmcli/config@4.0.0 ([5e744c8](https://www.github.com/npm/init-package-json/commit/5e744c8269a75acfb93ce00a8472532873ffdb47)) 174 | * update read requirement from ~1.0.1 to ^1.0.7 ([4425b9a](https://www.github.com/npm/init-package-json/commit/4425b9af9ba4136f4df13ad84cfb541312d4eadf)) 175 | 176 | ## [2.0.0](https://github.com/npm/init-package-json/compare/v1.10.3...v2.0.0) (2020-10-09) 177 | * BREAKING: requires node10+ 178 | * fix: compat with new `@npmcli/config` module 179 | * chore: update deps to latest and greatest 180 | 181 | <a name="1.10.3"></a> 182 | ## [1.10.3](https://github.com/npm/init-package-json/compare/v1.10.2...v1.10.3) (2018-03-07) 183 | 184 | 185 | 186 | <a name="1.10.2"></a> 187 | ## [1.10.2](https://github.com/npm/init-package-json/compare/v1.10.1...v1.10.2) (2018-03-07) 188 | 189 | 190 | ### Bug Fixes 191 | 192 | * **default-input:** Catch errors from npa ([#71](https://github.com/npm/init-package-json/issues/71)) ([11aee1e](https://github.com/npm/init-package-json/commit/11aee1e)) 193 | * **grammar:** Fix minor style issue in final prompt ([#76](https://github.com/npm/init-package-json/issues/76)) ([ba259ce](https://github.com/npm/init-package-json/commit/ba259ce)) 194 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | <!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> 2 | 3 | All interactions in this repo are covered by the [npm Code of 4 | Conduct](https://docs.npmjs.com/policies/conduct) 5 | 6 | The npm cli team may, at its own discretion, moderate, remove, or edit 7 | any interactions such as pull requests, issues, and comments. 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | <!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> 2 | 3 | # Contributing 4 | 5 | ## Code of Conduct 6 | 7 | All interactions in the **npm** organization on GitHub are considered to be covered by our standard [Code of Conduct](https://docs.npmjs.com/policies/conduct). 8 | 9 | ## Reporting Bugs 10 | 11 | Before submitting a new bug report please search for an existing or similar report. 12 | 13 | Use one of our existing issue templates if you believe you've come across a unique problem. 14 | 15 | Duplicate issues, or issues that don't use one of our templates may get closed without a response. 16 | 17 | ## Pull Request Conventions 18 | 19 | ### Commits 20 | 21 | We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). 22 | 23 | When opening a pull request please be sure that either the pull request title, or each commit in the pull request, has one of the following prefixes: 24 | 25 | - `feat`: For when introducing a new feature. The result will be a new semver minor version of the package when it is next published. 26 | - `fix`: For bug fixes. The result will be a new semver patch version of the package when it is next published. 27 | - `docs`: For documentation updates. The result will be a new semver patch version of the package when it is next published. 28 | - `chore`: For changes that do not affect the published module. Often these are changes to tests. The result will be *no* change to the version of the package when it is next published (as the commit does not affect the published version). 29 | 30 | ### Test Coverage 31 | 32 | Pull requests made against this repo will run `npm test` automatically. Please make sure tests pass locally before submitting a PR. 33 | 34 | Every new feature or bug fix should come with a corresponding test or tests that validate the solutions. Testing also reports on code coverage and will fail if code coverage drops. 35 | 36 | ### Linting 37 | 38 | Linting is also done automatically once tests pass. `npm run lintfix` will fix most linting errors automatically. 39 | 40 | Please make sure linting passes before submitting a PR. 41 | 42 | ## What _not_ to contribute? 43 | 44 | ### Dependencies 45 | 46 | It should be noted that our team does not accept third-party dependency updates/PRs. If you submit a PR trying to update our dependencies we will close it with or without a reference to these contribution guidelines. 47 | 48 | ### Tools/Automation 49 | 50 | Our core team is responsible for the maintenance of the tooling/automation in this project and we ask contributors to not make changes to these when contributing (e.g. `.github/*`, `.eslintrc.json`, `.licensee.json`). Most of those files also have a header at the top to remind folks they are automatically generated. Pull requests that alter these will not be accepted. 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright npm, Inc. 4 | 5 | Permission to use, copy, modify, and/or distribute this 6 | software for any purpose with or without fee is hereby 7 | granted, provided that the above copyright notice and this 8 | permission notice appear in all copies. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL 11 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 12 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 13 | EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT, 14 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 16 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 17 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 18 | USE OR PERFORMANCE OF THIS SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # init-package-json 2 | 3 | A node module to get your node module started. 4 | 5 | ## Usage 6 | 7 | ```javascript 8 | const init = require('init-package-json') 9 | const path = require('path') 10 | 11 | // a path to a promzard module. In the event that this file is 12 | // not found, one will be provided for you. 13 | const initFile = path.resolve(process.env.HOME, '.npm-init') 14 | 15 | // the dir where we're doin stuff. 16 | const dir = process.cwd() 17 | 18 | // extra stuff that gets put into the PromZard module's context. 19 | // In npm, this is the resolved config object. Exposed as 'config' 20 | // Optional. 21 | const configData = { some: 'extra stuff' } 22 | 23 | // Any existing stuff from the package.json file is also exposed in the 24 | // PromZard module as the `package` object. There will also be three 25 | // vars for: 26 | // * `filename` path to the package.json file 27 | // * `basename` the tip of the package dir 28 | // * `dirname` the parent of the package dir 29 | 30 | const data = await init(dir, initFile, configData) 31 | // the data's already been written to {dir}/package.json 32 | // now you can do stuff with it 33 | ``` 34 | 35 | See [PromZard](https://github.com/npm/promzard) for details about 36 | what can go in the config file. 37 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | <!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> 2 | 3 | GitHub takes the security of our software products and services seriously, including the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). 4 | 5 | If you believe you have found a security vulnerability in this GitHub-owned open source repository, you can report it to us in one of two ways. 6 | 7 | If the vulnerability you have found is *not* [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) or if you do not wish to be considered for a bounty reward, please report the issue to us directly through [opensource-security@github.com](mailto:opensource-security@github.com). 8 | 9 | If the vulnerability you have found is [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) and you would like for your finding to be considered for a bounty reward, please submit the vulnerability to us through [HackerOne](https://hackerone.com/github) in order to be eligible to receive a bounty award. 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 12 | 13 | Thanks for helping make GitHub safe for everyone. 14 | -------------------------------------------------------------------------------- /lib/default-input.js: -------------------------------------------------------------------------------- 1 | /* globals config, dirname, package, basename, yes, prompt */ 2 | 3 | const fs = require('fs/promises') 4 | const path = require('path') 5 | const validateLicense = require('validate-npm-package-license') 6 | const validateName = require('validate-npm-package-name') 7 | const npa = require('npm-package-arg') 8 | const semver = require('semver') 9 | 10 | // more popular packages should go here, maybe? 11 | const testPkgs = [ 12 | 'coco', 13 | 'coffee-script', 14 | 'expresso', 15 | 'jasmine', 16 | 'jest', 17 | 'mocha', 18 | 'streamline', 19 | 'tap', 20 | ] 21 | const isTestPkg = p => testPkgs.includes(p) 22 | 23 | const invalid = (msg) => Object.assign(new Error(msg), { notValid: true }) 24 | 25 | const readDeps = (test, excluded) => async () => { 26 | const dirs = await fs.readdir('node_modules').catch(() => null) 27 | 28 | if (!dirs) { 29 | return 30 | } 31 | 32 | const deps = {} 33 | for (const dir of dirs) { 34 | if (dir.match(/^\./) || test !== isTestPkg(dir) || excluded[dir]) { 35 | continue 36 | } 37 | 38 | const dp = path.join(dirname, 'node_modules', dir, 'package.json') 39 | const p = await fs.readFile(dp, 'utf8').then((d) => JSON.parse(d)).catch(() => null) 40 | 41 | if (!p || !p.version || p?._requiredBy?.some((r) => r === '#USER')) { 42 | continue 43 | } 44 | 45 | deps[dir] = config.get('save-exact') ? p.version : config.get('save-prefix') + p.version 46 | } 47 | 48 | return deps 49 | } 50 | 51 | const getConfig = (key) => { 52 | // dots take precedence over dashes 53 | const def = config?.defaults?.[`init.${key}`] 54 | const val = config.get(`init.${key}`) 55 | return (val !== def && val) ? val : config.get(`init-${key.replace(/\./g, '-')}`) 56 | } 57 | 58 | const getName = () => { 59 | const rawName = package.name || basename 60 | let name = rawName 61 | .replace(/^node-|[.-]js$/g, '') 62 | .replace(/\s+/g, ' ') 63 | .replace(/ /g, '-') 64 | .toLowerCase() 65 | 66 | let spec 67 | try { 68 | spec = npa(name) 69 | } catch { 70 | spec = {} 71 | } 72 | 73 | let scope = config.get('scope') 74 | 75 | if (scope) { 76 | if (scope.charAt(0) !== '@') { 77 | scope = '@' + scope 78 | } 79 | if (spec.scope) { 80 | name = scope + '/' + spec.name.split('/')[1] 81 | } else { 82 | name = scope + '/' + name 83 | } 84 | } 85 | 86 | return name 87 | } 88 | 89 | const name = getName() 90 | exports.name = yes ? name : prompt('package name', name, (data) => { 91 | const its = validateName(data) 92 | if (its.validForNewPackages) { 93 | return data 94 | } 95 | const errors = (its.errors || []).concat(its.warnings || []) 96 | return invalid(`Sorry, ${errors.join(' and ')}.`) 97 | }) 98 | 99 | const version = package.version || getConfig('version') || '1.0.0' 100 | exports.version = yes ? version : prompt('version', version, (v) => { 101 | if (semver.valid(v)) { 102 | return v 103 | } 104 | return invalid(`Invalid version: "${v}"`) 105 | }) 106 | 107 | if (!package.description) { 108 | exports.description = yes ? '' : prompt('description') 109 | } 110 | 111 | if (!package.main) { 112 | exports.main = async () => { 113 | const files = await fs.readdir(dirname) 114 | .then(list => list.filter((f) => f.match(/\.js$/))) 115 | .catch(() => []) 116 | 117 | let index 118 | if (files.includes('index.js')) { 119 | index = 'index.js' 120 | } else if (files.includes('main.js')) { 121 | index = 'main.js' 122 | } else if (files.includes(basename + '.js')) { 123 | index = basename + '.js' 124 | } else { 125 | index = files[0] || 'index.js' 126 | } 127 | 128 | return yes ? index : prompt('entry point', index) 129 | } 130 | } 131 | 132 | if (!package.bin) { 133 | exports.bin = async () => { 134 | try { 135 | const d = await fs.readdir(path.resolve(dirname, 'bin')) 136 | // just take the first js file we find there, or nada 137 | let r = d.find(f => f.match(/\.js$/)) 138 | if (r) { 139 | r = `bin/${r}` 140 | } 141 | return r 142 | } catch { 143 | // no bins 144 | } 145 | } 146 | } 147 | 148 | exports.directories = async () => { 149 | const dirs = await fs.readdir(dirname) 150 | 151 | const res = dirs.reduce((acc, d) => { 152 | if (/^examples?$/.test(d)) { 153 | acc.example = d 154 | } else if (/^tests?$/.test(d)) { 155 | acc.test = d 156 | } else if (/^docs?$/.test(d)) { 157 | acc.doc = d 158 | } else if (d === 'man') { 159 | acc.man = d 160 | } else if (d === 'lib') { 161 | acc.lib = d 162 | } 163 | 164 | return acc 165 | }, {}) 166 | 167 | return Object.keys(res).length === 0 ? undefined : res 168 | } 169 | 170 | if (!package.dependencies) { 171 | exports.dependencies = readDeps(false, package.devDependencies || {}) 172 | } 173 | 174 | if (!package.devDependencies) { 175 | exports.devDependencies = readDeps(true, package.dependencies || {}) 176 | } 177 | 178 | // MUST have a test script! 179 | if (!package.scripts) { 180 | const scripts = package.scripts || {} 181 | const notest = 'echo "Error: no test specified" && exit 1' 182 | exports.scripts = async () => { 183 | const d = await fs.readdir(path.join(dirname, 'node_modules')).catch(() => []) 184 | 185 | // check to see what framework is in use, if any 186 | let command 187 | if (!scripts.test || scripts.test === notest) { 188 | const commands = { 189 | tap: 'tap test/*.js', 190 | expresso: 'expresso test', 191 | mocha: 'mocha', 192 | } 193 | for (const [k, v] of Object.entries(commands)) { 194 | if (d.includes(k)) { 195 | command = v 196 | } 197 | } 198 | } 199 | 200 | const promptArgs = ['test command', (t) => t || notest] 201 | if (command) { 202 | promptArgs.splice(1, 0, command) 203 | } 204 | scripts.test = yes ? command || notest : prompt(...promptArgs) 205 | 206 | return scripts 207 | } 208 | } 209 | 210 | if (!package.repository) { 211 | exports.repository = async () => { 212 | const gitConfigPath = path.resolve(dirname, '.git', 'config') 213 | const gconf = await fs.readFile(gitConfigPath, 'utf8').catch(() => '') 214 | const lines = gconf.split(/\r?\n/) 215 | 216 | let url 217 | const i = lines.indexOf('[remote "origin"]') 218 | 219 | if (i !== -1) { 220 | url = lines[i + 1] 221 | if (!url.match(/^\s*url =/)) { 222 | url = lines[i + 2] 223 | } 224 | if (!url.match(/^\s*url =/)) { 225 | url = null 226 | } else { 227 | url = url.replace(/^\s*url = /, '') 228 | } 229 | } 230 | 231 | if (url && url.match(/^git@github.com:/)) { 232 | url = url.replace(/^git@github.com:/, 'https://github.com/') 233 | } 234 | 235 | return yes ? url || '' : prompt('git repository', url || undefined) 236 | } 237 | } 238 | 239 | if (!package.keywords) { 240 | exports.keywords = yes ? '' : prompt('keywords', (data) => { 241 | if (!data) { 242 | return 243 | } 244 | if (Array.isArray(data)) { 245 | data = data.join(' ') 246 | } 247 | if (typeof data !== 'string') { 248 | return data 249 | } 250 | return data.split(/[\s,]+/) 251 | }) 252 | } 253 | 254 | if (!package.author) { 255 | const authorName = getConfig('author.name') 256 | exports.author = authorName 257 | ? { 258 | name: authorName, 259 | email: getConfig('author.email'), 260 | url: getConfig('author.url'), 261 | } 262 | : yes ? '' : prompt('author') 263 | } 264 | 265 | const license = package.license || getConfig('license') || 'ISC' 266 | exports.license = yes ? license : prompt('license', license, (data) => { 267 | const its = validateLicense(data) 268 | if (its.validForNewPackages) { 269 | return data 270 | } 271 | const errors = (its.errors || []).concat(its.warnings || []) 272 | return invalid(`Sorry, ${errors.join(' and ')}.`) 273 | }) 274 | 275 | const type = package.type || getConfig('type') || 'commonjs' 276 | exports.type = yes ? type : prompt('type', type, (data) => { 277 | return data 278 | }) 279 | 280 | // Only include private field if it already exists or if explicitly set in config 281 | const configPrivate = getConfig('private') 282 | if (package.private !== undefined || configPrivate !== undefined) { 283 | if (package.private !== undefined) { 284 | exports.private = package.private 285 | } else if (!config.isDefault || !config.isDefault('init-private')) { 286 | exports.private = configPrivate 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /lib/init-package-json.js: -------------------------------------------------------------------------------- 1 | 2 | const promzard = require('promzard') 3 | const path = require('path') 4 | const semver = require('semver') 5 | const { read } = require('read') 6 | const util = require('util') 7 | const PackageJson = require('@npmcli/package-json') 8 | 9 | const def = require.resolve('./default-input.js') 10 | 11 | const extras = [ 12 | 'bundleDependencies', 13 | 'gypfile', 14 | 'serverjs', 15 | 'scriptpath', 16 | 'readme', 17 | 'bin', 18 | 'githead', 19 | 'fillTypes', 20 | 'normalizeData', 21 | ] 22 | 23 | const isYes = (c) => !!(c.get('yes') || c.get('y') || c.get('force') || c.get('f')) 24 | 25 | const getConfig = (c) => { 26 | // accept either a plain-jane object, or a config object with a "get" method. 27 | if (typeof c.get !== 'function') { 28 | const data = c 29 | return { 30 | get: (k) => data[k], 31 | toJSON: () => data, 32 | } 33 | } 34 | return c 35 | } 36 | 37 | // Coverage disabled because this is just walking back the fixPeople 38 | // normalization from the normalizeData step and we don't need to re-test all 39 | // of those paths. 40 | /* istanbul ignore next */ 41 | const stringifyPerson = (p) => { 42 | const { name, url, web, email, mail } = p 43 | const u = url || web 44 | const e = email || mail 45 | return `${name}${e ? ` <${e}>` : ''}${u ? ` (${u})` : ''}` 46 | } 47 | async function init (dir, 48 | // TODO test for non-default definitions 49 | /* istanbul ignore next */ 50 | input = def, 51 | c = {}) { 52 | const config = getConfig(c) 53 | const yes = isYes(config) 54 | const packageFile = path.resolve(dir, 'package.json') 55 | 56 | // read what's already there to inform our prompts 57 | const pkg = await PackageJson.load(dir, { create: true }) 58 | await pkg.normalize() 59 | 60 | if (!semver.valid(pkg.content.version)) { 61 | delete pkg.content.version 62 | } 63 | 64 | // make sure that the input is valid. if not, use the default 65 | const pzData = await promzard(path.resolve(input), { 66 | yes, 67 | config, 68 | filename: packageFile, 69 | dirname: dir, 70 | basename: path.basename(dir), 71 | package: pkg.content, 72 | }, { backupFile: def }) 73 | 74 | for (const [k, v] of Object.entries(pzData)) { 75 | if (v != null) { 76 | pkg.content[k] = v 77 | } 78 | } 79 | 80 | await pkg.normalize({ steps: extras }) 81 | 82 | // turn the objects back into somewhat more humane strings. 83 | // "normalizeData" does this and there isn't a way to choose which of those steps happen 84 | if (pkg.content.author) { 85 | pkg.content.author = stringifyPerson(pkg.content.author) 86 | } 87 | 88 | // no need for the readme now. 89 | delete pkg.content.readme 90 | delete pkg.content.readmeFilename 91 | 92 | // really don't want to have this lying around in the file 93 | delete pkg.content._id 94 | 95 | // ditto 96 | delete pkg.content.gitHead 97 | 98 | // if the repo is empty, remove it. 99 | if (!pkg.content.repository) { 100 | delete pkg.content.repository 101 | } 102 | 103 | // readJson filters out empty descriptions, but init-package-json 104 | // traditionally leaves them alone 105 | if (!pkg.content.description) { 106 | pkg.content.description = pzData.description 107 | } 108 | 109 | // optionalDependencies don't need to be repeated in two places 110 | if (pkg.content.dependencies) { 111 | if (pkg.content.optionalDependencies) { 112 | for (const name of Object.keys(pkg.content.optionalDependencies)) { 113 | delete pkg.content.dependencies[name] 114 | } 115 | } 116 | if (Object.keys(pkg.content.dependencies).length === 0) { 117 | delete pkg.content.dependencies 118 | } 119 | } 120 | 121 | const stringified = JSON.stringify(pkg.content, null, 2) + '\n' 122 | const msg = util.format('%s:\n\n%s\n', packageFile, stringified) 123 | 124 | if (yes) { 125 | await pkg.save() 126 | if (!config.get('silent')) { 127 | // eslint-disable-next-line no-console 128 | console.log(`Wrote to ${msg}`) 129 | } 130 | return pkg.content 131 | } 132 | 133 | // eslint-disable-next-line no-console 134 | console.log(`About to write to ${msg}`) 135 | const ok = await read({ prompt: 'Is this OK? ', default: 'yes' }) 136 | if (!ok || !ok.toLowerCase().startsWith('y')) { 137 | // eslint-disable-next-line no-console 138 | console.log('Aborted.') 139 | return 140 | } 141 | 142 | await pkg.save({ sort: true }) 143 | return pkg.content 144 | } 145 | 146 | module.exports = init 147 | module.exports.yes = isYes 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "init-package-json", 3 | "version": "8.2.1", 4 | "main": "lib/init-package-json.js", 5 | "scripts": { 6 | "test": "tap", 7 | "lint": "npm run eslint", 8 | "postlint": "template-oss-check", 9 | "lintfix": "npm run eslint -- --fix", 10 | "snap": "tap", 11 | "posttest": "npm run lint", 12 | "template-oss-apply": "template-oss-apply --force", 13 | "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/npm/init-package-json.git" 18 | }, 19 | "author": "GitHub Inc.", 20 | "license": "ISC", 21 | "description": "A node module to get your node module started", 22 | "dependencies": { 23 | "@npmcli/package-json": "^6.1.0", 24 | "npm-package-arg": "^12.0.0", 25 | "promzard": "^2.0.0", 26 | "read": "^4.0.0", 27 | "semver": "^7.3.5", 28 | "validate-npm-package-license": "^3.0.4", 29 | "validate-npm-package-name": "^6.0.0" 30 | }, 31 | "devDependencies": { 32 | "@npmcli/config": "^10.0.0", 33 | "@npmcli/eslint-config": "^5.0.0", 34 | "@npmcli/template-oss": "4.23.4", 35 | "tap": "^16.0.1" 36 | }, 37 | "engines": { 38 | "node": "^20.17.0 || >=22.9.0" 39 | }, 40 | "tap": { 41 | "test-ignore": "fixtures/", 42 | "nyc-arg": [ 43 | "--exclude", 44 | "tap-snapshots/**" 45 | ], 46 | "timeout": 300 47 | }, 48 | "keywords": [ 49 | "init", 50 | "package.json", 51 | "package", 52 | "helper", 53 | "wizard", 54 | "wizerd", 55 | "prompt", 56 | "start" 57 | ], 58 | "files": [ 59 | "bin/", 60 | "lib/" 61 | ], 62 | "templateOSS": { 63 | "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", 64 | "version": "4.23.4", 65 | "publish": true 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "group-pull-request-title-pattern": "chore: release ${version}", 3 | "pull-request-title-pattern": "chore: release${component} ${version}", 4 | "changelog-sections": [ 5 | { 6 | "type": "feat", 7 | "section": "Features", 8 | "hidden": false 9 | }, 10 | { 11 | "type": "fix", 12 | "section": "Bug Fixes", 13 | "hidden": false 14 | }, 15 | { 16 | "type": "docs", 17 | "section": "Documentation", 18 | "hidden": false 19 | }, 20 | { 21 | "type": "deps", 22 | "section": "Dependencies", 23 | "hidden": false 24 | }, 25 | { 26 | "type": "chore", 27 | "section": "Chores", 28 | "hidden": true 29 | } 30 | ], 31 | "packages": { 32 | ".": { 33 | "package-name": "" 34 | } 35 | }, 36 | "prerelease-type": "pre" 37 | } 38 | -------------------------------------------------------------------------------- /test/basic.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | const fs = require('node:fs/promises') 4 | const path = require('node:path') 5 | 6 | if (isChild()) { 7 | return child() 8 | } 9 | 10 | t.test('the basics', async (t) => { 11 | const { data } = await setup(t, __filename, { 12 | inputFile: 'basic', 13 | config: { foo: 'bar' }, 14 | inputs: [ 15 | [/name: \(.*\) $/, 'the-name'], 16 | [/description: $/, 'description'], 17 | [/OK\? \(.*\) $/, 'yes'], 18 | ], 19 | }) 20 | t.same(data, { 21 | name: 'the-name', 22 | version: '1.2.5', 23 | description: 'description', 24 | author: 'npmbot <n@p.m> (http://npm.im)', 25 | scripts: { test: 'make test' }, 26 | main: 'main.js', 27 | config: { foo: 'bar' }, 28 | package: {}, 29 | }) 30 | }) 31 | 32 | t.test('no config', async (t) => { 33 | const { data } = await setup(t, __filename, { 34 | inputFile: 'basic', 35 | inputs: [ 36 | [/name: \(.*\) $/, 'the-name'], 37 | [/description: $/, 'description'], 38 | [/OK\? \(.*\) $/, 'yes'], 39 | ], 40 | }) 41 | t.same(data, { 42 | name: 'the-name', 43 | version: '1.2.5', 44 | description: 'description', 45 | author: 'npmbot <n@p.m> (http://npm.im)', 46 | scripts: { test: 'make test' }, 47 | main: 'main.js', 48 | config: {}, 49 | package: {}, 50 | }) 51 | }) 52 | 53 | t.test('no save', async (t) => { 54 | const { tdir, data, output } = await setup(t, __filename, { 55 | inputFile: 'basic', 56 | config: { foo: 'bar' }, 57 | inputs: [ 58 | [/name: \(.*\) $/, 'the-name'], 59 | [/description: $/, 'description'], 60 | [/OK\? \(.*\) $/, 'no'], 61 | ], 62 | }) 63 | t.same(data, undefined) 64 | t.match(output, 'Aborted') 65 | await t.rejects(fs.stat(path.join(tdir, 'package.json')), 'did not write a package.json file') 66 | }) 67 | -------------------------------------------------------------------------------- /test/bins.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('auto bin population', async (t) => { 9 | const { data } = await setup(t, __filename, { 10 | testdir: { 11 | bin: { 'run.js': '' }, 12 | }, 13 | inputs: { 14 | name: 'auto-bin-test', 15 | }, 16 | }) 17 | t.same(data.bin, { 'auto-bin-test': 'bin/run.js' }, 18 | 'bin auto populated with correct path') 19 | }) 20 | -------------------------------------------------------------------------------- /test/dependencies.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child({ chdir: true }) 6 | } 7 | 8 | t.test('read in dependencies and dev deps', async (t) => { 9 | const testdirContents = { 10 | 'package.json': JSON.stringify({ 11 | dependencies: { 12 | abbrev: '*', 13 | tap: '*', 14 | }, 15 | optionalDependencies: { 16 | abbrev: '*', 17 | }, 18 | }), 19 | node_modules: {}, 20 | } 21 | 22 | for (const fakedep of ['mocha', 'tap', 'async', 'foobar']) { 23 | testdirContents.node_modules[fakedep] = { 24 | 'package.json': JSON.stringify({ 25 | name: fakedep, 26 | version: '1.0.0', 27 | }), 28 | } 29 | } 30 | 31 | const { data } = await setup(t, __filename, { 32 | testdir: testdirContents, 33 | config: { yes: 'yes', 'save-prefix': '^' }, 34 | }) 35 | 36 | t.same(data, { 37 | name: 'tap-testdir-dependencies-read-in-dependencies-and-dev-deps', 38 | version: '1.0.0', 39 | type: 'commonjs', 40 | description: '', 41 | author: '', 42 | scripts: { test: 'mocha' }, 43 | main: 'index.js', 44 | keywords: [], 45 | license: 'ISC', 46 | dependencies: { 47 | tap: '*', 48 | }, 49 | devDependencies: { 50 | mocha: '^1.0.0', 51 | }, 52 | optionalDependencies: { 53 | abbrev: '*', 54 | }, 55 | }, 'used the correct dependency information') 56 | }) 57 | -------------------------------------------------------------------------------- /test/fixtures/basic.fixture.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | package = {} 3 | exports.name = prompt('name', package.name || basename) 4 | exports.version = '1.2.5' 5 | exports.description = prompt('description', package.description) 6 | exports.author = 'npmbot <n@p.m> (http://npm.im)' 7 | exports.scripts = package.scripts || {} 8 | exports.scripts.test = 'make test' 9 | exports.main = package.main || 'main.js' 10 | exports.config = config && JSON.parse(JSON.stringify(config)) 11 | try { 12 | delete exports.config.config 13 | } catch (e) { 14 | // ok 15 | } 16 | try { 17 | delete exports.package.config 18 | } catch (e) { 19 | // ok 20 | } 21 | try { 22 | delete exports.package.package 23 | } catch (e) { 24 | // ok 25 | } 26 | try { 27 | delete exports.config.package 28 | } catch (e) { 29 | // ok 30 | } 31 | exports.package = JSON.parse(JSON.stringify(package)) 32 | -------------------------------------------------------------------------------- /test/fixtures/setup.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process') 2 | const path = require('path') 3 | const init = require('../../') 4 | 5 | const CHILD = 'child' 6 | 7 | const isChild = () => process.argv[2] === CHILD 8 | 9 | const setup = async (t, file, { 10 | config, 11 | inputFile = '', 12 | inputs = [], 13 | testdir = {}, 14 | dir, 15 | } = {}) => { 16 | let tdir = t.testdir(testdir) 17 | if (dir) { 18 | tdir = path.join(tdir, dir) 19 | } 20 | 21 | inputs = Array.isArray(inputs) ? inputs : validInput(inputs) 22 | 23 | const args = [file, CHILD, tdir, inputFile] 24 | if (config) { 25 | args.push(JSON.stringify(config)) 26 | } 27 | 28 | let i = 0 29 | let stderr = '' 30 | let stdout = '' 31 | 32 | await new Promise((res, rej) => { 33 | const proc = spawn(process.execPath, args) 34 | proc.stderr.on('data', c => stderr += c) 35 | proc.stdout.on('data', (c) => { 36 | stdout += c 37 | 38 | const next = inputs[i] 39 | const [prompt, write] = Array.isArray(next) ? next : [null, next] 40 | 41 | if (write == null || typeof prompt?.test === 'function' && !prompt.test(stdout)) { 42 | return 43 | } 44 | 45 | i++ 46 | const last = i === inputs.length 47 | setTimeout(() => proc.stdin[last ? 'end' : 'write'](`${write}\n`), 100) 48 | }) 49 | proc.on('close', res) 50 | proc.on('error', rej) 51 | }) 52 | 53 | try { 54 | return { 55 | tdir, 56 | data: stderr ? JSON.parse(stderr) : null, 57 | output: stdout, 58 | } 59 | } catch (er) { 60 | console.error(stderr) 61 | throw er 62 | } 63 | } 64 | 65 | const getFixture = (f) => path.join(__dirname, `${path.basename(f, '.js')}.fixture.js`) 66 | 67 | async function child ({ chdir } = {}) { 68 | const [dir, input, config] = process.argv.slice(3) 69 | 70 | if (chdir) { 71 | process.chdir(dir) 72 | } 73 | 74 | const output = await init(dir, getFixture(input), config && JSON.parse(config)) 75 | if (output !== undefined) { 76 | console.error(JSON.stringify(output)) 77 | } 78 | } 79 | 80 | const standardValue = (value) => { 81 | if (Array.isArray(value) && Array.isArray(value[0])) { 82 | return value 83 | } 84 | return [value] 85 | } 86 | 87 | const validInput = (obj) => { 88 | return [ 89 | ...standardValue(obj.name || ''), 90 | ...standardValue(obj.version || ''), 91 | ...standardValue(obj.description || ''), 92 | ...standardValue(obj.entry || ''), 93 | ...standardValue(obj.test || ''), 94 | ...standardValue(obj.repo || ''), 95 | ...standardValue(obj.keywords || ''), 96 | ...standardValue(obj.author || ''), 97 | ...standardValue(obj.licence || ''), 98 | ...standardValue(obj.type || ''), 99 | ...standardValue(obj.ok || 'yes'), 100 | ] 101 | } 102 | 103 | module.exports = { setup, child, isChild, getFixture } 104 | -------------------------------------------------------------------------------- /test/license.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('license', async (t) => { 9 | const { data } = await setup(t, __filename, { 10 | inputs: { 11 | name: 'the-name', 12 | licence: [ 13 | [/license: \(.*\) $/, 'Apache'], // invalid license 14 | [/license: \(.*\) $/, 'Apache-2.0'], // license 15 | ], 16 | }, 17 | }) 18 | 19 | const wanted = { 20 | name: 'the-name', 21 | version: '1.0.0', 22 | description: '', 23 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 24 | license: 'Apache-2.0', 25 | author: '', 26 | main: 'index.js', 27 | } 28 | t.has(data, wanted) 29 | }) 30 | -------------------------------------------------------------------------------- /test/name-default-formatting.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('replaces spaces for hyphens', async t => { 9 | const { data } = await setup(t, __filename, { 10 | testdir: { 11 | 'name with spaces': {}, 12 | }, 13 | dir: 'name with spaces', 14 | config: { yes: 'yes' }, 15 | }) 16 | 17 | t.equal(data.name, 'name-with-spaces') 18 | }) 19 | 20 | t.test('removes node- and .js', async t => { 21 | const { data } = await setup(t, __filename, { 22 | testdir: { 23 | 'node-package.js': {}, 24 | }, 25 | dir: 'node-package.js', 26 | config: { yes: 'yes' }, 27 | }) 28 | 29 | t.equal(data.name, 'package') 30 | }) 31 | 32 | t.test('capital letters and multiple spaces', async t => { 33 | const { data } = await setup(t, __filename, { 34 | testdir: { 35 | 'capital letters and multiple spaces': {}, 36 | }, 37 | dir: 'capital letters and multiple spaces', 38 | config: { yes: 'yes' }, 39 | }) 40 | 41 | t.equal(data.name, 'capital-letters-and-multiple-spaces') 42 | }) 43 | -------------------------------------------------------------------------------- /test/name-spaces.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('single space', async t => { 9 | const { data } = await setup(t, __filename, { 10 | inputs: { 11 | name: [ 12 | [/name: \(.*\) $/, 'the name'], // invalid package name 13 | [/name: \(.*\) $/, 'the-name'], // package name 14 | ], 15 | }, 16 | }) 17 | 18 | const wanted = { 19 | name: 'the-name', 20 | version: '1.0.0', 21 | description: '', 22 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 23 | license: 'ISC', 24 | author: '', 25 | main: 'index.js', 26 | } 27 | t.has(data, wanted) 28 | }) 29 | 30 | t.test('multiple spaces', async t => { 31 | const { data } = await setup(t, __filename, { 32 | inputs: { 33 | name: [ 34 | [/name: \(.*\) $/, 'the name should be this'], // invalid package name 35 | [/name: \(.*\) $/, 'the-name-should-be-this'], // package name 36 | ], 37 | }, 38 | }) 39 | 40 | const wanted = { 41 | name: 'the-name-should-be-this', 42 | version: '1.0.0', 43 | description: '', 44 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 45 | license: 'ISC', 46 | author: '', 47 | main: 'index.js', 48 | } 49 | t.has(data, wanted) 50 | }) 51 | -------------------------------------------------------------------------------- /test/name-uppercase.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('uppercase', async (t) => { 9 | const { data } = await setup(t, __filename, { 10 | inputs: { 11 | name: [ 12 | [/name: \(.*\) $/, 'THE-NAME'], 13 | [/name: \(.*\) $/, 'the-name'], 14 | ], 15 | }, 16 | }) 17 | 18 | const EXPECT = { 19 | name: 'the-name', 20 | version: '1.0.0', 21 | description: '', 22 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 23 | license: 'ISC', 24 | author: '', 25 | main: 'index.js', 26 | } 27 | t.has(data, EXPECT) 28 | }) 29 | -------------------------------------------------------------------------------- /test/npm-defaults.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { resolve } = require('path') 3 | const Config = require('@npmcli/config') 4 | const init = require('../') 5 | const cwd = process.cwd() 6 | 7 | // npm config 8 | const definitions = { 9 | registry: { 10 | key: 'registry', 11 | description: 'registry', 12 | default: 'https://registry.npmjs.org/', 13 | type: ['', Config.typeDefs.url.type], 14 | }, 15 | 'init-module': { 16 | key: 'init-module', 17 | description: 'init module config', 18 | default: '~/.npm-init.js', 19 | type: Config.typeDefs.path.type, 20 | }, 21 | 'init-author-name': { 22 | key: 'init-author-name', 23 | description: 'init author name config', 24 | default: '', 25 | type: String, 26 | }, 27 | 'init-author-email': { 28 | key: 'init-author-email', 29 | description: 'init author email config', 30 | default: '', 31 | type: String, 32 | }, 33 | 'init-author-url': { 34 | key: 'init-author-url', 35 | description: 'init author url config', 36 | default: '', 37 | type: ['', Config.typeDefs.url.type], 38 | }, 39 | 'init-license': { 40 | key: 'init-license', 41 | description: 'init license config', 42 | default: 'ISC', 43 | type: String, 44 | }, 45 | 'init-version': { 46 | key: 'init-version', 47 | description: 'init version config', 48 | default: '1.0.0', 49 | type: Config.typeDefs.semver.type, 50 | }, 51 | 'init.module': { 52 | key: 'init-module', 53 | description: 'deprecated init module config', 54 | default: '~/.npm-init.js', 55 | type: Config.typeDefs.path.type, 56 | }, 57 | 'init.author.name': { 58 | key: 'init.author.name', 59 | description: 'deprecated init author name config', 60 | default: '', 61 | type: String, 62 | }, 63 | 'init.author.email': { 64 | key: 'init.author.email', 65 | description: 'deprecated init author email config', 66 | default: '', 67 | type: String, 68 | }, 69 | 'init.author.url': { 70 | key: 'init.author.url', 71 | description: 'deprecated init author url config', 72 | default: '', 73 | type: ['', Config.typeDefs.url.type], 74 | }, 75 | 'init.license': { 76 | key: 'init.license', 77 | description: 'deprecated init license config', 78 | default: 'ISC', 79 | type: String, 80 | }, 81 | 'init.version': { 82 | key: 'init.version', 83 | description: 'deprecated init version config', 84 | default: '1.0.0', 85 | type: Config.typeDefs.semver.type, 86 | }, 87 | } 88 | const shorthands = {} 89 | 90 | const EXPECTED = { 91 | name: 'test', 92 | version: '3.1.4', 93 | description: '', 94 | directories: { 95 | lib: 'lib', 96 | }, 97 | main: 'basic.js', 98 | scripts: { 99 | test: 'echo "Error: no test specified" && exit 1', 100 | }, 101 | keywords: [], 102 | author: 'npmbot <n@p.m> (http://npm.im/)', 103 | type: 'commonjs', 104 | license: 'WTFPL', 105 | } 106 | 107 | t.test('npm configuration values pulled from environment', async t => { 108 | t.teardown(() => { 109 | process.chdir(cwd) 110 | }) 111 | /* eslint camelcase:0 */ 112 | const env = { 113 | npm_config_yes: 'yes', 114 | npm_config_silent: 'true', 115 | npm_config_init_author_name: 'npmbot', 116 | npm_config_init_author_email: 'n@p.m', 117 | npm_config_init_author_url: 'http://npm.im', 118 | npm_config_init_license: EXPECTED.license, 119 | npm_config_init_version: EXPECTED.version, 120 | } 121 | 122 | const testdir = t.testdir({ 123 | npm: {}, 124 | 'package.json': JSON.stringify({ 125 | name: EXPECTED.name, 126 | main: EXPECTED.main, 127 | directories: EXPECTED.directories, 128 | }), 129 | }) 130 | 131 | const conf = new Config({ 132 | env, 133 | argv: [], 134 | cwd: testdir, 135 | npmPath: resolve(testdir, 'npm'), 136 | definitions, 137 | shorthands, 138 | }) 139 | 140 | await conf.load() 141 | conf.validate() 142 | 143 | process.chdir(testdir) 144 | 145 | const data = await init(testdir, testdir, conf) 146 | t.same(data, EXPECTED, 'got the package data from the environment') 147 | }) 148 | 149 | t.test('npm configuration values pulled from dotted config', async t => { 150 | t.teardown(() => { 151 | process.chdir(cwd) 152 | }) 153 | const testdir = t.testdir({ 154 | npm: {}, 155 | 'package.json': JSON.stringify({ 156 | name: EXPECTED.name, 157 | main: EXPECTED.main, 158 | directories: EXPECTED.directories, 159 | }), 160 | '.npmrc': ` 161 | yes=true 162 | silent=true 163 | 164 | init.author.name=npmbot 165 | init.author.email=n@p.m 166 | init.author.url=http://npm.im 167 | 168 | init.license=${EXPECTED.license} 169 | init.version=${EXPECTED.version}`, 170 | }) 171 | 172 | const conf = new Config({ 173 | env: {}, 174 | argv: [], 175 | cwd: testdir, 176 | npmPath: resolve(testdir, 'npm'), 177 | definitions, 178 | shorthands, 179 | }) 180 | 181 | await conf.load() 182 | conf.validate() 183 | 184 | process.chdir(testdir) 185 | 186 | const data = await init(testdir, testdir, conf) 187 | t.same(data, EXPECTED, 'got the package data from the config') 188 | }) 189 | 190 | t.test('npm configuration values pulled from dashed config', async t => { 191 | t.teardown(() => { 192 | process.chdir(cwd) 193 | }) 194 | const testdir = t.testdir({ 195 | npm: {}, 196 | 'package.json': JSON.stringify({ 197 | name: EXPECTED.name, 198 | main: EXPECTED.main, 199 | directories: EXPECTED.directories, 200 | }), 201 | '.npmrc': ` 202 | yes=true 203 | silent=true 204 | 205 | init-author-name=npmbot 206 | init-author-email=n@p.m 207 | init-author-url=http://npm.im 208 | 209 | init-license=${EXPECTED.license} 210 | init-version=${EXPECTED.version}`, 211 | }) 212 | 213 | const conf = new Config({ 214 | env: {}, 215 | argv: [], 216 | cwd: testdir, 217 | npmPath: resolve(testdir, 'npm'), 218 | definitions, 219 | shorthands, 220 | }) 221 | 222 | await conf.load() 223 | conf.validate() 224 | 225 | process.chdir(testdir) 226 | 227 | const data = await init(testdir, testdir, conf) 228 | t.same(data, EXPECTED, 'got the package data from the config') 229 | }) 230 | -------------------------------------------------------------------------------- /test/private-defaults.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('private field with init-private true', async (t) => { 9 | const { data } = await setup(t, __filename, { 10 | config: { yes: 'yes', 'init-private': true }, 11 | }) 12 | 13 | t.equal(data.private, true, 'private field set to true in yes mode') 14 | }) 15 | 16 | t.test('private field with init-private false', async (t) => { 17 | const { data } = await setup(t, __filename, { 18 | config: { yes: 'yes', 'init-private': false }, 19 | }) 20 | 21 | t.equal(data.private, false, 'private field set to false is undefined') 22 | }) 23 | 24 | t.test('private field without init-private', async (t) => { 25 | const { data } = await setup(t, __filename, { 26 | config: { yes: 'yes' }, 27 | }) 28 | 29 | t.equal(data.private, undefined, 'private not set in by default') 30 | }) 31 | 32 | t.test('respects existing private field in package.json', async (t) => { 33 | const { data } = await setup(t, __filename, { 34 | testdir: { 35 | 'package.json': JSON.stringify({ 36 | name: 'existing-package', 37 | version: '1.0.0', 38 | private: true, 39 | }), 40 | }, 41 | config: { yes: 'yes' }, 42 | }) 43 | 44 | t.equal(data.private, true, 'keeps existing private value from package.json') 45 | }) 46 | 47 | t.test('existing private field takes precedence over config', async (t) => { 48 | const { data } = await setup(t, __filename, { 49 | testdir: { 50 | 'package.json': JSON.stringify({ 51 | name: 'existing-package', 52 | version: '1.0.0', 53 | private: true, 54 | }), 55 | }, 56 | config: { yes: 'yes', 'init-private': false }, 57 | }) 58 | 59 | t.equal(data.private, true, 'existing package.json private field takes precedence over config') 60 | }) 61 | 62 | t.test('adds private from config when existing package has no private field', async t => { 63 | const { data } = await setup(t, __filename, { 64 | testdir: { 65 | 'package.json': JSON.stringify({ 66 | name: 'existing-package', 67 | version: '1.0.0', 68 | }), 69 | }, 70 | config: { yes: 'yes', 'init-private': true }, 71 | }) 72 | 73 | t.equal(data.private, true, 'adds private field from config when not in existing package') 74 | }) 75 | -------------------------------------------------------------------------------- /test/repository.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('license', async (t) => { 9 | const { data } = await setup(t, __filename, { 10 | inputs: { name: 'the-name', repo: 'npm/cli' }, 11 | }) 12 | 13 | const wanted = { 14 | name: 'the-name', 15 | version: '1.0.0', 16 | description: '', 17 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 18 | author: '', 19 | repository: { 20 | type: 'git', 21 | url: 'git+https://github.com/npm/cli.git', 22 | }, 23 | main: 'index.js', 24 | type: 'commonjs', 25 | } 26 | t.has(data, wanted) 27 | }) 28 | 29 | t.test('repository from git config', async (t) => { 30 | const testdir = { 31 | '.git': { 32 | config: ` 33 | [remote "origin"] 34 | url = https://github.com/npm/cli.git`, 35 | } } 36 | 37 | const { data } = await setup(t, __filename, { 38 | config: { yes: 'yes' }, 39 | testdir, 40 | }) 41 | 42 | const wanted = { 43 | type: 'git', 44 | url: 'git+https://github.com/npm/cli.git', 45 | } 46 | t.has(data.repository, wanted) 47 | }) 48 | -------------------------------------------------------------------------------- /test/scope-in-config-existing-name.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('with existing package.json', async (t) => { 9 | const { data } = await setup(t, __filename, { 10 | testdir: { 11 | 'package.json': JSON.stringify({ 12 | name: '@already/scoped', 13 | version: '1.0.0', 14 | }), 15 | }, 16 | config: { yes: 'yes', scope: '@still' }, 17 | }) 18 | 19 | t.equal(data.name, '@still/scoped', 'new scope is added, basic name is kept') 20 | }) 21 | -------------------------------------------------------------------------------- /test/scope-in-config.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('--yes with scope', async (t) => { 9 | const EXPECT = { 10 | name: '@scoped/tap-testdir-scope-in-config---yes-with-scope', 11 | version: '1.0.0', 12 | description: '', 13 | author: '', 14 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 15 | main: 'index.js', 16 | keywords: [], 17 | license: 'ISC', 18 | } 19 | 20 | const { data } = await setup(t, __filename, { 21 | config: { yes: 'yes', scope: '@scoped' }, 22 | }) 23 | 24 | t.has(data, EXPECT) 25 | }) 26 | -------------------------------------------------------------------------------- /test/scope.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('the scope', async (t) => { 9 | const EXPECT = { 10 | name: '@foo/test', 11 | version: '1.2.5', 12 | description: 'description', 13 | author: 'npmbot <n@p.m> (http://npm.im)', 14 | scripts: { test: 'make test' }, 15 | main: 'main.js', 16 | config: { scope: '@foo' }, 17 | package: {}, 18 | } 19 | 20 | const { data } = await setup(t, __filename, { 21 | inputFile: 'basic', 22 | config: { scope: '@foo' }, 23 | inputs: [ 24 | '@foo/test', 25 | 'description', 26 | 'yes', 27 | ], 28 | }) 29 | 30 | t.has(data, EXPECT) 31 | }) 32 | -------------------------------------------------------------------------------- /test/silent.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('silent: true', async (t) => { 9 | const { output } = await setup(t, __filename, { 10 | config: { yes: 'yes', silent: true }, 11 | }) 12 | 13 | t.equal(output, '', 'did not print anything') 14 | }) 15 | -------------------------------------------------------------------------------- /test/yes-defaults.js: -------------------------------------------------------------------------------- 1 | const t = require('tap') 2 | const { setup, child, isChild } = require('./fixtures/setup') 3 | 4 | if (isChild()) { 5 | return child() 6 | } 7 | 8 | t.test('--yes defaults', async (t) => { 9 | const EXPECT = { 10 | name: 'tap-testdir-yes-defaults---yes-defaults', 11 | version: '1.0.0', 12 | description: '', 13 | author: '', 14 | scripts: { test: 'echo "Error: no test specified" && exit 1' }, 15 | main: 'index.js', 16 | keywords: [], 17 | license: 'ISC', 18 | } 19 | 20 | const { data } = await setup(t, __filename, { 21 | config: { yes: 'yes' }, 22 | }) 23 | 24 | t.has(data, EXPECT, 'used the default data') 25 | }) 26 | --------------------------------------------------------------------------------