├── .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 |
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 |
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 |
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 |
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 |
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 (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 (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 (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 (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 (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 |
--------------------------------------------------------------------------------