diff --git a/.commitlintrc.js b/.commitlintrc.js
new file mode 100644
index 0000000..5b0b1a5
--- /dev/null
+++ b/.commitlintrc.js
@@ -0,0 +1,10 @@
+/* This file is automatically added by @npmcli/template-oss. Do not edit. */
+
+module.exports = {
+ extends: ['@commitlint/config-conventional'],
+ rules: {
+ 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'deps', 'chore']],
+ 'header-max-length': [2, 'always', 80],
+ 'subject-case': [0, 'always', ['lower-case', 'sentence-case', 'start-case']],
+ },
+}
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..5db9f81
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,17 @@
+/* This file is automatically added by @npmcli/template-oss. Do not edit. */
+
+'use strict'
+
+const { readdirSync: readdir } = require('fs')
+
+const localConfigs = readdir(__dirname)
+ .filter((file) => file.startsWith('.eslintrc.local.'))
+ .map((file) => `./${file}`)
+
+module.exports = {
+ root: true,
+ extends: [
+ '@npmcli',
+ ...localConfigs,
+ ],
+}
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..2c54b0d
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,3 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+* @npm/cli-team
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 0000000..d043192
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,54 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: Bug
+description: File a bug/issue
+title: "[BUG]
"
+labels: [ Bug, Needs Triage ]
+
+body:
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please [search here](./issues) to see if an issue already exists for your problem.
+ options:
+ - label: I have searched the existing issues
+ required: true
+ - type: textarea
+ attributes:
+ label: Current Behavior
+ description: A clear & concise description of what you're experiencing.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Expected Behavior
+ description: A clear & concise description of what you expected to happen.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Steps To Reproduce
+ description: Steps to reproduce the behavior.
+ value: |
+ 1. In this environment...
+ 2. With this config...
+ 3. Run '...'
+ 4. See error...
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Environment
+ description: |
+ examples:
+ - **npm**: 7.6.3
+ - **Node**: 13.14.0
+ - **OS**: Ubuntu 20.04
+ - **platform**: Macbook Pro
+ value: |
+ - npm:
+ - Node:
+ - OS:
+ - platform:
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..d640909
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,3 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+blank_issues_enabled: true
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..8da2a45
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,17 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+version: 2
+
+updates:
+ - package-ecosystem: npm
+ directory: /
+ schedule:
+ interval: daily
+ allow:
+ - dependency-type: direct
+ versioning-strategy: increase-if-necessary
+ commit-message:
+ prefix: deps
+ prefix-development: chore
+ labels:
+ - "Dependencies"
diff --git a/.github/matchers/tap.json b/.github/matchers/tap.json
new file mode 100644
index 0000000..2c81ea9
--- /dev/null
+++ b/.github/matchers/tap.json
@@ -0,0 +1,32 @@
+{
+ "//@npmcli/template-oss": "This file is automatically added by @npmcli/template-oss. Do not edit.",
+ "problemMatcher": [
+ {
+ "owner": "tap",
+ "pattern": [
+ {
+ "regexp": "^\\s*not ok \\d+ - (.*)",
+ "message": 1
+ },
+ {
+ "regexp": "^\\s*---"
+ },
+ {
+ "regexp": "^\\s*at:"
+ },
+ {
+ "regexp": "^\\s*line:\\s*(\\d+)",
+ "line": 1
+ },
+ {
+ "regexp": "^\\s*column:\\s*(\\d+)",
+ "column": 1
+ },
+ {
+ "regexp": "^\\s*file:\\s*(.*)",
+ "file": 1
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml
new file mode 100644
index 0000000..62892f9
--- /dev/null
+++ b/.github/workflows/audit.yml
@@ -0,0 +1,39 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: Audit
+
+on:
+ workflow_dispatch:
+ schedule:
+ # "At 08:00 UTC (01:00 PT) on Monday" https://crontab.guru/#0_8_*_*_1
+ - cron: "0 8 * * 1"
+
+jobs:
+ audit:
+ name: Audit Dependencies
+ if: github.repository_owner == 'npm'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund --package-lock
+ - name: Run Production Audit
+ run: npm audit --omit=dev
+ - name: Run Full Audit
+ run: npm audit --audit-level=none
diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml
new file mode 100644
index 0000000..6e80aa6
--- /dev/null
+++ b/.github/workflows/ci-release.yml
@@ -0,0 +1,216 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: CI - Release
+
+on:
+ workflow_dispatch:
+ inputs:
+ ref:
+ required: true
+ type: string
+ default: main
+ workflow_call:
+ inputs:
+ ref:
+ required: true
+ type: string
+ check-sha:
+ required: true
+ type: string
+
+jobs:
+ lint-all:
+ name: Lint All
+ if: github.repository_owner == 'npm'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Get Workflow Job
+ uses: actions/github-script@v6
+ if: inputs.check-sha
+ id: check-output
+ env:
+ JOB_NAME: "Lint All"
+ MATRIX_NAME: ""
+ with:
+ script: |
+ const { owner, repo } = context.repo
+
+ const { data } = await github.rest.actions.listJobsForWorkflowRun({
+ owner,
+ repo,
+ run_id: context.runId,
+ per_page: 100
+ })
+
+ const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME
+ const job = data.jobs.find(j => j.name.endsWith(jobName))
+ const jobUrl = job?.html_url
+
+ const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}`
+
+ let summary = `This check is assosciated with ${shaUrl}\n\n`
+
+ if (jobUrl) {
+ summary += `For run logs, click here: ${jobUrl}`
+ } else {
+ summary += `Run logs could not be found for a job with name: "${jobName}"`
+ }
+
+ return { summary }
+ - name: Create Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ id: check
+ if: inputs.check-sha
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ status: in_progress
+ name: Lint All
+ sha: ${{ inputs.check-sha }}
+ output: ${{ steps.check-output.outputs.result }}
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Lint
+ run: npm run lint --ignore-scripts
+ - name: Post Lint
+ run: npm run postlint --ignore-scripts
+ - name: Conclude Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ if: steps.check.outputs.check_id && always()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ conclusion: ${{ job.status }}
+ check_id: ${{ steps.check.outputs.check_id }}
+
+ test-all:
+ name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }}
+ if: github.repository_owner == 'npm'
+ strategy:
+ fail-fast: false
+ matrix:
+ platform:
+ - name: Linux
+ os: ubuntu-latest
+ shell: bash
+ - name: macOS
+ os: macos-latest
+ shell: bash
+ - name: Windows
+ os: windows-latest
+ shell: cmd
+ node-version:
+ - 14.17.0
+ - 14.x
+ - 16.13.0
+ - 16.x
+ - 18.0.0
+ - 18.x
+ runs-on: ${{ matrix.platform.os }}
+ defaults:
+ run:
+ shell: ${{ matrix.platform.shell }}
+ steps:
+ - name: Get Workflow Job
+ uses: actions/github-script@v6
+ if: inputs.check-sha
+ id: check-output
+ env:
+ JOB_NAME: "Test All"
+ MATRIX_NAME: " - ${{ matrix.platform.name }} - ${{ matrix.node-version }}"
+ with:
+ script: |
+ const { owner, repo } = context.repo
+
+ const { data } = await github.rest.actions.listJobsForWorkflowRun({
+ owner,
+ repo,
+ run_id: context.runId,
+ per_page: 100
+ })
+
+ const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME
+ const job = data.jobs.find(j => j.name.endsWith(jobName))
+ const jobUrl = job?.html_url
+
+ const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}`
+
+ let summary = `This check is assosciated with ${shaUrl}\n\n`
+
+ if (jobUrl) {
+ summary += `For run logs, click here: ${jobUrl}`
+ } else {
+ summary += `Run logs could not be found for a job with name: "${jobName}"`
+ }
+
+ return { summary }
+ - name: Create Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ id: check
+ if: inputs.check-sha
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ status: in_progress
+ name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }}
+ sha: ${{ inputs.check-sha }}
+ output: ${{ steps.check-output.outputs.result }}
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: Update Windows npm
+ # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows
+ if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.'))
+ run: |
+ curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz
+ tar xf npm-7.5.4.tgz
+ cd package
+ node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz
+ cd ..
+ rmdir /s /q package
+ - name: Install npm@7
+ if: startsWith(matrix.node-version, '10.')
+ run: npm i --prefer-online --no-fund --no-audit -g npm@7
+ - name: Install npm@latest
+ if: ${{ !startsWith(matrix.node-version, '10.') }}
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Add Problem Matcher
+ run: echo "::add-matcher::.github/matchers/tap.json"
+ - name: Test
+ run: npm test --ignore-scripts
+ - name: Conclude Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ if: steps.check.outputs.check_id && always()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ conclusion: ${{ job.status }}
+ check_id: ${{ steps.check.outputs.check_id }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..9cc149d
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,107 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: CI
+
+on:
+ workflow_dispatch:
+ pull_request:
+ push:
+ branches:
+ - main
+ - latest
+ schedule:
+ # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1
+ - cron: "0 9 * * 1"
+
+jobs:
+ lint:
+ name: Lint
+ if: github.repository_owner == 'npm'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Lint
+ run: npm run lint --ignore-scripts
+ - name: Post Lint
+ run: npm run postlint --ignore-scripts
+
+ test:
+ name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }}
+ if: github.repository_owner == 'npm'
+ strategy:
+ fail-fast: false
+ matrix:
+ platform:
+ - name: Linux
+ os: ubuntu-latest
+ shell: bash
+ - name: macOS
+ os: macos-latest
+ shell: bash
+ - name: Windows
+ os: windows-latest
+ shell: cmd
+ node-version:
+ - 14.17.0
+ - 14.x
+ - 16.13.0
+ - 16.x
+ - 18.0.0
+ - 18.x
+ runs-on: ${{ matrix.platform.os }}
+ defaults:
+ run:
+ shell: ${{ matrix.platform.shell }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: Update Windows npm
+ # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows
+ if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.'))
+ run: |
+ curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz
+ tar xf npm-7.5.4.tgz
+ cd package
+ node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz
+ cd ..
+ rmdir /s /q package
+ - name: Install npm@7
+ if: startsWith(matrix.node-version, '10.')
+ run: npm i --prefer-online --no-fund --no-audit -g npm@7
+ - name: Install npm@latest
+ if: ${{ !startsWith(matrix.node-version, '10.') }}
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Add Problem Matcher
+ run: echo "::add-matcher::.github/matchers/tap.json"
+ - name: Test
+ run: npm test --ignore-scripts
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..66b9498
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,38 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: CodeQL
+
+on:
+ push:
+ branches:
+ - main
+ - latest
+ pull_request:
+ branches:
+ - main
+ - latest
+ schedule:
+ # "At 10:00 UTC (03:00 PT) on Monday" https://crontab.guru/#0_10_*_*_1
+ - cron: "0 10 * * 1"
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: javascript
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml
new file mode 100644
index 0000000..19902bd
--- /dev/null
+++ b/.github/workflows/post-dependabot.yml
@@ -0,0 +1,121 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: Post Dependabot
+
+on: pull_request
+
+permissions:
+ contents: write
+
+jobs:
+ template-oss:
+ name: template-oss
+ if: github.repository_owner == 'npm' && github.actor == 'dependabot[bot]'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.pull_request.head.ref }}
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Fetch Dependabot Metadata
+ id: metadata
+ uses: dependabot/fetch-metadata@v1
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
+ # Dependabot can update multiple directories so we output which directory
+ # it is acting on so we can run the command for the correct root or workspace
+ - name: Get Dependabot Directory
+ if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss')
+ id: flags
+ run: |
+ dependabot_dir="${{ steps.metadata.outputs.directory }}"
+ if [[ "$dependabot_dir" == "/" ]]; then
+ echo "::set-output name=workspace::-iwr"
+ else
+ # strip leading slash from directory so it works as a
+ # a path to the workspace flag
+ echo "::set-output name=workspace::-w ${dependabot_dir#/}"
+ fi
+
+ - name: Apply Changes
+ if: steps.flags.outputs.workspace
+ id: apply
+ run: |
+ npm run template-oss-apply ${{ steps.flags.outputs.workspace }}
+ if [[ `git status --porcelain` ]]; then
+ echo "::set-output name=changes::true"
+ fi
+ # This only sets the conventional commit prefix. This workflow can't reliably determine
+ # what the breaking change is though. If a BREAKING CHANGE message is required then
+ # this PR check will fail and the commit will be amended with stafftools
+ if [[ "${{ steps.metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then
+ prefix='feat!'
+ else
+ prefix='chore'
+ fi
+ echo "::set-output name=message::$prefix: postinstall for dependabot template-oss PR"
+
+ # This step will fail if template-oss has made any workflow updates. It is impossible
+ # for a workflow to update other workflows. In the case it does fail, we continue
+ # and then try to apply only a portion of the changes in the next step
+ - name: Push All Changes
+ if: steps.apply.outputs.changes
+ id: push
+ continue-on-error: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ git commit -am "${{ steps.apply.outputs.message }}"
+ git push
+
+ # If the previous step failed, then reset the commit and remove any workflow changes
+ # and attempt to commit and push again. This is helpful because we will have a commit
+ # with the correct prefix that we can then --amend with @npmcli/stafftools later.
+ - name: Push All Changes Except Workflows
+ if: steps.apply.outputs.changes && steps.push.outcome == 'failure'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ git reset HEAD~
+ git checkout HEAD -- .github/workflows/
+ git clean -fd .github/workflows/
+ git commit -am "${{ steps.apply.outputs.message }}"
+ git push
+
+ # Check if all the necessary template-oss changes were applied. Since we continued
+ # on errors in one of the previous steps, this check will fail if our follow up
+ # only applied a portion of the changes and we need to followup manually.
+ #
+ # Note that this used to run `lint` and `postlint` but that will fail this action
+ # if we've also shipped any linting changes separate from template-oss. We do
+ # linting in another action, so we want to fail this one only if there are
+ # template-oss changes that could not be applied.
+ - name: Check Changes
+ if: steps.apply.outputs.changes
+ run: |
+ npm exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check
+
+ - name: Fail on Breaking Change
+ if: steps.apply.outputs.changes && startsWith(steps.apply.outputs.message, 'feat!')
+ run: |
+ echo "This PR has a breaking change. Run 'npx -p @npmcli/stafftools gh template-oss-fix'"
+ echo "for more information on how to fix this with a BREAKING CHANGE footer."
+ exit 1
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
new file mode 100644
index 0000000..1a1d1ee
--- /dev/null
+++ b/.github/workflows/pull-request.yml
@@ -0,0 +1,48 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: Pull Request
+
+on:
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - edited
+ - synchronize
+
+jobs:
+ commitlint:
+ name: Lint Commits
+ if: github.repository_owner == 'npm'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Run Commitlint on Commits
+ id: commit
+ continue-on-error: true
+ run: |
+ npx --offline commitlint -V --from origin/${{ github.base_ref }} --to ${{ github.event.pull_request.head.sha }}
+ - name: Run Commitlint on PR Title
+ if: steps.commit.outcome == 'failure'
+ run: |
+ echo ${{ github.event.pull_request.title }} | npx --offline commitlint -V
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..264cf3d
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,299 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+name: Release
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ - latest
+ - release/v*
+
+permissions:
+ contents: write
+ pull-requests: write
+ checks: write
+
+jobs:
+ release:
+ outputs:
+ pr: ${{ steps.release.outputs.pr }}
+ releases: ${{ steps.release.outputs.releases }}
+ release-flags: ${{ steps.release.outputs.release-flags }}
+ branch: ${{ steps.release.outputs.pr-branch }}
+ pr-number: ${{ steps.release.outputs.pr-number }}
+ comment-id: ${{ steps.pr-comment.outputs.result }}
+ check-id: ${{ steps.check.outputs.check_id }}
+ name: Release
+ if: github.repository_owner == 'npm'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Release Please
+ id: release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ npx --offline template-oss-release-please ${{ github.ref_name }} ${{ github.event_name }}
+ - name: Post Pull Request Comment
+ if: steps.release.outputs.pr-number
+ uses: actions/github-script@v6
+ id: pr-comment
+ env:
+ PR_NUMBER: ${{ steps.release.outputs.pr-number }}
+ REF_NAME: ${{ github.ref_name }}
+ with:
+ script: |
+ const { REF_NAME, PR_NUMBER } = process.env
+ const repo = { owner: context.repo.owner, repo: context.repo.repo }
+ const issue = { ...repo, issue_number: PR_NUMBER }
+
+ const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId })
+
+ let body = '## Release Manager\n\n'
+
+ const comments = await github.paginate(github.rest.issues.listComments, issue)
+ let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id
+
+ body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Update This Release\n\n`
+ body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`main\`. `
+ body += `To force CI to update this PR, run this command:\n\n`
+ body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\``
+
+ if (commentId) {
+ await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body })
+ } else {
+ const { data: comment } = await github.rest.issues.createComment({ ...issue, body })
+ commentId = comment?.id
+ }
+
+ return commentId
+ - name: Get Workflow Job
+ uses: actions/github-script@v6
+ if: steps.release.outputs.pr-sha
+ id: check-output
+ env:
+ JOB_NAME: "Release"
+ MATRIX_NAME: ""
+ with:
+ script: |
+ const { owner, repo } = context.repo
+
+ const { data } = await github.rest.actions.listJobsForWorkflowRun({
+ owner,
+ repo,
+ run_id: context.runId,
+ per_page: 100
+ })
+
+ const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME
+ const job = data.jobs.find(j => j.name.endsWith(jobName))
+ const jobUrl = job?.html_url
+
+ const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.release.outputs.pr-sha }}`
+
+ let summary = `This check is assosciated with ${shaUrl}\n\n`
+
+ if (jobUrl) {
+ summary += `For run logs, click here: ${jobUrl}`
+ } else {
+ summary += `Run logs could not be found for a job with name: "${jobName}"`
+ }
+
+ return { summary }
+ - name: Create Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ id: check
+ if: steps.release.outputs.pr-sha
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ status: in_progress
+ name: Release
+ sha: ${{ steps.release.outputs.pr-sha }}
+ output: ${{ steps.check-output.outputs.result }}
+
+ update:
+ needs: release
+ outputs:
+ sha: ${{ steps.commit.outputs.sha }}
+ check-id: ${{ steps.check.outputs.check_id }}
+ name: Update - Release
+ if: github.repository_owner == 'npm' && needs.release.outputs.pr
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ ref: ${{ needs.release.outputs.branch }}
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Run Post Pull Request Actions
+ env:
+ RELEASE_PR_NUMBER: ${{ needs.release.outputs.pr-number }}
+ RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ npm exec --offline -- template-oss-release-manager --lockfile=false
+ npm run rp-pull-request --ignore-scripts --if-present
+ - name: Commit
+ id: commit
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ git commit --all --amend --no-edit || true
+ git push --force-with-lease
+ echo "::set-output name=sha::$(git rev-parse HEAD)"
+ - name: Get Workflow Job
+ uses: actions/github-script@v6
+ if: steps.commit.outputs.sha
+ id: check-output
+ env:
+ JOB_NAME: "Update - Release"
+ MATRIX_NAME: ""
+ with:
+ script: |
+ const { owner, repo } = context.repo
+
+ const { data } = await github.rest.actions.listJobsForWorkflowRun({
+ owner,
+ repo,
+ run_id: context.runId,
+ per_page: 100
+ })
+
+ const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME
+ const job = data.jobs.find(j => j.name.endsWith(jobName))
+ const jobUrl = job?.html_url
+
+ const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.commit.outputs.sha }}`
+
+ let summary = `This check is assosciated with ${shaUrl}\n\n`
+
+ if (jobUrl) {
+ summary += `For run logs, click here: ${jobUrl}`
+ } else {
+ summary += `Run logs could not be found for a job with name: "${jobName}"`
+ }
+
+ return { summary }
+ - name: Create Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ id: check
+ if: steps.commit.outputs.sha
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ status: in_progress
+ name: Release
+ sha: ${{ steps.commit.outputs.sha }}
+ output: ${{ steps.check-output.outputs.result }}
+ - name: Conclude Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ if: needs.release.outputs.check-id && always()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ conclusion: ${{ job.status }}
+ check_id: ${{ needs.release.outputs.check-id }}
+
+ ci:
+ name: CI - Release
+ needs: [ release, update ]
+ if: needs.release.outputs.pr
+ uses: ./.github/workflows/ci-release.yml
+ with:
+ ref: ${{ needs.release.outputs.branch }}
+ check-sha: ${{ needs.update.outputs.sha }}
+
+ post-ci:
+ needs: [ release, update, ci ]
+ name: Post CI - Release
+ if: github.repository_owner == 'npm' && needs.release.outputs.pr && always()
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Get Needs Result
+ id: needs-result
+ run: |
+ result=""
+ if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then
+ result="failure"
+ elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
+ result="cancelled"
+ else
+ result="success"
+ fi
+ echo "::set-output name=result::$result"
+ - name: Conclude Check
+ uses: LouisBrunner/checks-action@v1.3.1
+ if: needs.update.outputs.check-id && always()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ conclusion: ${{ steps.needs-result.outputs.result }}
+ check_id: ${{ needs.update.outputs.check-id }}
+
+ post-release:
+ needs: release
+ name: Post Release - Release
+ if: github.repository_owner == 'npm' && needs.release.outputs.releases
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Git User
+ run: |
+ git config --global user.email "npm-cli+bot@github.com"
+ git config --global user.name "npm CLI robot"
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+ - name: Install npm@latest
+ run: npm i --prefer-online --no-fund --no-audit -g npm@latest
+ - name: npm Version
+ run: npm -v
+ - name: Install Dependencies
+ run: npm i --ignore-scripts --no-audit --no-fund
+ - name: Run Post Release Actions
+ env:
+ RELEASES: ${{ needs.release.outputs.releases }}
+ run: |
+ npm run rp-release --ignore-scripts --if-present ${{ join(fromJSON(needs.release.outputs.release-flags), ' ') }}
diff --git a/.gitignore b/.gitignore
index 902c5dd..0ec3c84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,28 @@
-/coverage
-/.nyc_output
-/node_modules
-package-lock.json
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+# ignore everything in the root
+/*
+
+# keep these
+!**/.gitignore
+!/.commitlintrc.js
+!/.eslintrc.js
+!/.eslintrc.local.*
+!/.github/
+!/.gitignore
+!/.npmrc
+!/.release-please-manifest.json
+!/bin/
+!/CHANGELOG*
+!/CODE_OF_CONDUCT.md
+!/docs/
+!/lib/
+!/LICENSE*
+!/map.js
+!/package.json
+!/README*
+!/release-please-config.json
+!/scripts/
+!/SECURITY.md
+!/tap-snapshots/
+!/test/
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..529f93e
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,3 @@
+; This file is automatically added by @npmcli/template-oss. Do not edit.
+
+package-lock=false
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
new file mode 100644
index 0000000..969d3db
--- /dev/null
+++ b/.release-please-manifest.json
@@ -0,0 +1,3 @@
+{
+ ".": "2.1.0"
+}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 09263d7..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: node_js
-sudo: false
-
-node_js:
- - node
- - 12
- - 10
- - 8
-
-os:
- - linux
-
-cache:
- directories:
- - $HOME/.npm
-
-notifications:
- email: false
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..167043c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,7 @@
+
+
+All interactions in this repo are covered by the [npm Code of
+Conduct](https://docs.npmjs.com/policies/conduct)
+
+The npm cli team may, at its own discretion, moderate, remove, or edit
+any interactions such as pull requests, issues, and comments.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..4e7c26c
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,14 @@
+
+
+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).
+
+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.
+
+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 using [private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability).
+
+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.
+
+**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
+
+Thanks for helping make GitHub safe for everyone.
+
diff --git a/index.js b/lib/index.js
similarity index 84%
rename from index.js
rename to lib/index.js
index 9b0779c..f3f2a88 100644
--- a/index.js
+++ b/lib/index.js
@@ -3,21 +3,7 @@ const MiniPass = require('minipass')
const EE = require('events').EventEmitter
const fs = require('fs')
-let writev = fs.writev
-/* istanbul ignore next */
-if (!writev) {
- // This entire block can be removed if support for earlier than Node.js
- // 12.9.0 is not needed.
- const binding = process.binding('fs')
- const FSReqWrap = binding.FSReqWrap || binding.FSReqCallback
-
- writev = (fd, iovec, pos, cb) => {
- const done = (er, bw) => cb(er, bw, iovec)
- const req = new FSReqWrap()
- req.oncomplete = done
- binding.writeBuffers(fd, iovec, pos, req)
- }
-}
+const writev = fs.writev
const _autoClose = Symbol('_autoClose')
const _close = Symbol('_close')
@@ -56,27 +42,34 @@ class ReadStream extends MiniPass {
this.readable = true
this.writable = false
- if (typeof path !== 'string')
+ if (typeof path !== 'string') {
throw new TypeError('path must be a string')
+ }
this[_errored] = false
this[_fd] = typeof opt.fd === 'number' ? opt.fd : null
this[_path] = path
- this[_readSize] = opt.readSize || 16*1024*1024
+ this[_readSize] = opt.readSize || 16 * 1024 * 1024
this[_reading] = false
this[_size] = typeof opt.size === 'number' ? opt.size : Infinity
this[_remain] = this[_size]
this[_autoClose] = typeof opt.autoClose === 'boolean' ?
opt.autoClose : true
- if (typeof this[_fd] === 'number')
+ if (typeof this[_fd] === 'number') {
this[_read]()
- else
+ } else {
this[_open]()
+ }
}
- get fd () { return this[_fd] }
- get path () { return this[_path] }
+ get fd () {
+ return this[_fd]
+ }
+
+ get path () {
+ return this[_path]
+ }
write () {
throw new TypeError('this is a readable stream')
@@ -91,9 +84,9 @@ class ReadStream extends MiniPass {
}
[_onopen] (er, fd) {
- if (er)
+ if (er) {
this[_onerror](er)
- else {
+ } else {
this[_fd] = fd
this.emit('open', fd)
this[_read]()
@@ -109,19 +102,21 @@ class ReadStream extends MiniPass {
this[_reading] = true
const buf = this[_makeBuf]()
/* istanbul ignore if */
- if (buf.length === 0)
+ if (buf.length === 0) {
return process.nextTick(() => this[_onread](null, 0, buf))
- fs.read(this[_fd], buf, 0, buf.length, null, (er, br, buf) =>
- this[_onread](er, br, buf))
+ }
+ fs.read(this[_fd], buf, 0, buf.length, null, (er, br, b) =>
+ this[_onread](er, br, b))
}
}
[_onread] (er, br, buf) {
this[_reading] = false
- if (er)
+ if (er) {
this[_onerror](er)
- else if (this[_handleChunk](br, buf))
+ } else if (this[_handleChunk](br, buf)) {
this[_read]()
+ }
}
[_close] () {
@@ -142,8 +137,9 @@ class ReadStream extends MiniPass {
let ret = false
// no effect if infinite
this[_remain] -= br
- if (br > 0)
+ if (br > 0) {
ret = super.write(br < buf.length ? buf.slice(0, br) : buf)
+ }
if (br === 0 || this[_remain] <= 0) {
ret = false
@@ -161,13 +157,15 @@ class ReadStream extends MiniPass {
break
case 'drain':
- if (typeof this[_fd] === 'number')
+ if (typeof this[_fd] === 'number') {
this[_read]()
+ }
break
case 'error':
- if (this[_errored])
+ if (this[_errored]) {
return
+ }
this[_errored] = true
return super.emit(ev, data)
@@ -184,8 +182,9 @@ class ReadStreamSync extends ReadStream {
this[_onopen](null, fs.openSync(this[_path], 'r'))
threw = false
} finally {
- if (threw)
+ if (threw) {
this[_close]()
+ }
}
}
@@ -199,15 +198,17 @@ class ReadStreamSync extends ReadStream {
/* istanbul ignore next */
const br = buf.length === 0 ? 0
: fs.readSync(this[_fd], buf, 0, buf.length, null)
- if (!this[_handleChunk](br, buf))
+ if (!this[_handleChunk](br, buf)) {
break
+ }
} while (true)
this[_reading] = false
}
threw = false
} finally {
- if (threw)
+ if (threw) {
this[_close]()
+ }
}
}
@@ -244,22 +245,28 @@ class WriteStream extends EE {
this[_defaultFlag] = opt.flags === undefined
this[_flags] = this[_defaultFlag] ? defaultFlag : opt.flags
- if (this[_fd] === null)
+ if (this[_fd] === null) {
this[_open]()
+ }
}
emit (ev, data) {
if (ev === 'error') {
- if (this[_errored])
+ if (this[_errored]) {
return
+ }
this[_errored] = true
}
return super.emit(ev, data)
}
+ get fd () {
+ return this[_fd]
+ }
- get fd () { return this[_fd] }
- get path () { return this[_path] }
+ get path () {
+ return this[_path]
+ }
[_onerror] (er) {
this[_close]()
@@ -278,9 +285,9 @@ class WriteStream extends EE {
er && er.code === 'ENOENT') {
this[_flags] = 'w'
this[_open]()
- } else if (er)
+ } else if (er) {
this[_onerror](er)
- else {
+ } else {
this[_fd] = fd
this.emit('open', fd)
this[_flush]()
@@ -288,21 +295,24 @@ class WriteStream extends EE {
}
end (buf, enc) {
- if (buf)
+ if (buf) {
this.write(buf, enc)
+ }
this[_ended] = true
// synthetic after-write logic, where drain/finish live
if (!this[_writing] && !this[_queue].length &&
- typeof this[_fd] === 'number')
+ typeof this[_fd] === 'number') {
this[_onwrite](null, 0)
+ }
return this
}
write (buf, enc) {
- if (typeof buf === 'string')
+ if (typeof buf === 'string') {
buf = Buffer.from(buf, enc)
+ }
if (this[_ended]) {
this.emit('error', new Error('write() after end()'))
@@ -326,14 +336,15 @@ class WriteStream extends EE {
}
[_onwrite] (er, bw) {
- if (er)
+ if (er) {
this[_onerror](er)
- else {
- if (this[_pos] !== null)
+ } else {
+ if (this[_pos] !== null) {
this[_pos] += bw
- if (this[_queue].length)
+ }
+ if (this[_queue].length) {
this[_flush]()
- else {
+ } else {
this[_writing] = false
if (this[_ended] && !this[_finished]) {
@@ -350,11 +361,12 @@ class WriteStream extends EE {
[_flush] () {
if (this[_queue].length === 0) {
- if (this[_ended])
+ if (this[_ended]) {
this[_onwrite](null, 0)
- } else if (this[_queue].length === 1)
+ }
+ } else if (this[_queue].length === 1) {
this[_write](this[_queue].pop())
- else {
+ } else {
const iovec = this[_queue]
this[_queue] = []
writev(this[_fd], iovec, this[_pos],
@@ -383,11 +395,13 @@ class WriteStreamSync extends WriteStream {
if (er.code === 'ENOENT') {
this[_flags] = 'w'
return this[_open]()
- } else
+ } else {
throw er
+ }
}
- } else
+ } else {
fd = fs.openSync(this[_path], this[_flags], this[_mode])
+ }
this[_onopen](null, fd)
}
@@ -409,8 +423,13 @@ class WriteStreamSync extends WriteStream {
fs.writeSync(this[_fd], buf, 0, buf.length, this[_pos]))
threw = false
} finally {
- if (threw)
- try { this[_close]() } catch (_) {}
+ if (threw) {
+ try {
+ this[_close]()
+ } catch {
+ // ok error
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index c555ce8..8bf2444 100644
--- a/package.json
+++ b/package.json
@@ -1,19 +1,22 @@
{
"name": "fs-minipass",
"version": "2.1.0",
- "main": "index.js",
+ "main": "lib/index.js",
"scripts": {
"test": "tap",
- "preversion": "npm test",
- "postversion": "npm publish",
- "postpublish": "git push origin --follow-tags"
+ "lint": "eslint \"**/*.js\"",
+ "postlint": "template-oss-check",
+ "template-oss-apply": "template-oss-apply --force",
+ "lintfix": "npm run lint -- --fix",
+ "snap": "tap",
+ "posttest": "npm run lint"
},
"keywords": [],
- "author": "Isaac Z. Schlueter (http://blog.izs.me/)",
+ "author": "GitHub Inc.",
"license": "ISC",
"repository": {
"type": "git",
- "url": "git+https://github.com/npm/fs-minipass.git"
+ "url": "https://github.com/npm/fs-minipass.git"
},
"bugs": {
"url": "https://github.com/npm/fs-minipass/issues"
@@ -24,16 +27,27 @@
"minipass": "^3.0.0"
},
"devDependencies": {
+ "@npmcli/eslint-config": "^4.0.0",
+ "@npmcli/template-oss": "^4.11.0",
"mutate-fs": "^2.0.1",
- "tap": "^15.0.10"
+ "tap": "^16.3.0"
},
"files": [
- "index.js"
+ "bin/",
+ "lib/"
],
"tap": {
- "check-coverage": true
+ "check-coverage": true,
+ "nyc-arg": [
+ "--exclude",
+ "tap-snapshots/**"
+ ]
},
"engines": {
- "node": ">= 8"
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ },
+ "templateOSS": {
+ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
+ "version": "4.11.0"
}
}
diff --git a/release-please-config.json b/release-please-config.json
new file mode 100644
index 0000000..73d1e35
--- /dev/null
+++ b/release-please-config.json
@@ -0,0 +1,36 @@
+{
+ "exclude-packages-from-root": true,
+ "group-pull-request-title-pattern": "chore: release ${version}",
+ "pull-request-title-pattern": "chore: release${component} ${version}",
+ "changelog-sections": [
+ {
+ "type": "feat",
+ "section": "Features",
+ "hidden": false
+ },
+ {
+ "type": "fix",
+ "section": "Bug Fixes",
+ "hidden": false
+ },
+ {
+ "type": "docs",
+ "section": "Documentation",
+ "hidden": false
+ },
+ {
+ "type": "deps",
+ "section": "Dependencies",
+ "hidden": false
+ },
+ {
+ "type": "chore",
+ "hidden": true
+ }
+ ],
+ "packages": {
+ ".": {
+ "package-name": ""
+ }
+ }
+}
diff --git a/test/read.js b/test/read.js
index f7d5f94..66f8e7c 100644
--- a/test/read.js
+++ b/test/read.js
@@ -3,11 +3,11 @@
const t = require('tap')
const fsm = require('../')
const fs = require('fs')
-const EE = require('events').EventEmitter
+const { resolve } = require('path')
const mutateFS = require('mutate-fs')
t.test('read the readme', t => {
- const p = __dirname + '/../README.md'
+ const p = resolve(__dirname, '..', 'README.md')
const rm = fs.readFileSync(p, 'utf8')
const check = (t, res) => {
t.equal(rm, res)
@@ -27,8 +27,9 @@ t.test('read the readme', t => {
t.type(str.fd, 'number')
const out = []
let chunk
- while (chunk = str.read())
+ while (chunk = str.read()) {
out.push(chunk)
+ }
check(t, out.join(''))
})
@@ -48,7 +49,7 @@ t.test('read the readme', t => {
})
t.test('read the readme sized', t => {
- const p = __dirname + '/../README.md'
+ const p = resolve(__dirname, '..', 'README.md')
const size = fs.statSync(p).size
const rm = fs.readFileSync(p, 'utf8')
const check = (t, res) => {
@@ -69,8 +70,9 @@ t.test('read the readme sized', t => {
t.equal(str.fd, null)
const out = []
let chunk
- while (chunk = str.read())
+ while (chunk = str.read()) {
out.push(chunk)
+ }
check(t, out.join(''))
})
@@ -98,10 +100,13 @@ t.test('slow sink', t => {
setTimeout(_ => this.emit('drain'))
return false
}
- end () { return this.write() }
+
+ end () {
+ return this.write()
+ }
}
- const p = __dirname + '/../README.md'
+ const p = resolve(__dirname, '..', 'README.md')
const rm = fs.readFileSync(p, 'utf8')
const check = t => {
t.equal(chunks.join(''), rm)
@@ -135,10 +140,11 @@ t.test('zeno reading style', t => {
chunks.push(chunk)
return true
}
+
end () {}
}
- const p = __dirname + '/../README.md'
+ const p = resolve(__dirname, '..', 'README.md')
const rm = fs.readFileSync(p, 'utf8')
const check = t => {
t.equal(chunks.join(''), rm)
@@ -213,33 +219,38 @@ t.test('fail read', t => {
})
fs.open = (path, flags, cb) => {
- if (path === __filename)
+ if (path === __filename) {
open(path, flags, (er, fd) => {
- if (!er)
+ if (!er) {
badFDs.add(fd)
+ }
return cb(er, fd)
})
- else
+ } else {
open(path, flags, cb)
+ }
}
fs.openSync = (path, flags) => {
const fd = openSync(path, flags)
- if (path === __filename)
+ if (path === __filename) {
badFDs.add(fd)
+ }
return fd
}
fs.read = function (fd, buf, offset, length, pos, cb) {
- if (badFDs.has(fd))
+ if (badFDs.has(fd)) {
process.nextTick(_ => cb(new Error('poop')))
- else
+ } else {
read(fd, buf, offset, length, pos, cb)
+ }
}
fs.readSync = function (fd, buf, offset, length, pos) {
- if (badFDs.has(fd))
+ if (badFDs.has(fd)) {
throw new Error('poop sync')
+ }
}
t.throws(_ => new fsm.ReadStreamSync(__filename))
@@ -256,7 +267,7 @@ t.test('fail read', t => {
})
t.test('fd test', t => {
- const p = __dirname + '/../README.md'
+ const p = resolve(__dirname, '..', 'README.md')
const rm = fs.readFileSync(p, 'utf8')
const check = (t, res) => {
t.equal(rm, res)
@@ -280,8 +291,9 @@ t.test('fd test', t => {
t.equal(str.path, p)
const out = []
let chunk
- while (chunk = str.read())
+ while (chunk = str.read()) {
out.push(chunk)
+ }
check(t, out.join(''))
})
@@ -300,7 +312,7 @@ t.test('fd test', t => {
})
t.test('fd test, no autoClose', t => {
- const p = __dirname + '/../README.md'
+ const p = resolve(__dirname, '..', 'README.md')
const rm = fs.readFileSync(p, 'utf8')
const check = (t, res, fd) => {
// will throw EBADF if already closed
@@ -314,7 +326,7 @@ t.test('fd test, no autoClose', t => {
const str = new fsm.ReadStreamSync(p, {
encoding: 'utf8',
fd: fd,
- autoClose: false
+ autoClose: false,
})
t.type(str.fd, 'number')
t.equal(str.path, p)
@@ -328,14 +340,15 @@ t.test('fd test, no autoClose', t => {
const str = new fsm.ReadStreamSync(p, {
encoding: 'utf8',
fd: fd,
- autoClose: false
+ autoClose: false,
})
t.type(str.fd, 'number')
t.equal(str.path, p)
const out = []
let chunk
- while (chunk = str.read())
+ while (chunk = str.read()) {
out.push(chunk)
+ }
check(t, out.join(''), fd)
})
@@ -344,7 +357,7 @@ t.test('fd test, no autoClose', t => {
const str = new fsm.ReadStream(p, {
encoding: 'utf8',
fd: fd,
- autoClose: false
+ autoClose: false,
})
t.type(str.fd, 'number')
t.equal(str.path, p)
diff --git a/test/write.js b/test/write.js
index 383d87d..3e2b85d 100644
--- a/test/write.js
+++ b/test/write.js
@@ -3,11 +3,11 @@
const t = require('tap')
const fsm = require('../')
const fs = require('fs')
-const EE = require('events').EventEmitter
+const { join } = require('path')
const mutateFS = require('mutate-fs')
t.test('basic write', t => {
- const p = __dirname + '/basic-write'
+ const p = join(__dirname, 'basic-write')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'ok')
@@ -30,7 +30,7 @@ t.test('basic write', t => {
})
t.test('write then end', t => {
- const p = __dirname + '/write-then-end'
+ const p = join(__dirname, '/write-then-end')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'okend')
@@ -62,7 +62,7 @@ t.test('write then end', t => {
})
t.test('multiple writes', t => {
- const p = __dirname + '/multiple-writes'
+ const p = join(__dirname, '/multiple-writes')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'abcdefghijklmnop')
@@ -128,22 +128,22 @@ t.test('multiple writes', t => {
t.ok(s.write('c'))
t.notOk(s.write('d'))
t.notOk(s.write('e'))
- s.once('drain', _ => {
+ s.once('drain', () => {
t.ok(s.write('f'))
t.notOk(s.write(Buffer.from('676869', 'hex')))
t.notOk(s.write('jklm'))
t.notOk(s.write(Buffer.from('nop')))
- s.once('drain', _ => s.end())
+ s.once('drain', () => s.end())
})
})
- s.on('finish', _ => check(t))
+ s.on('finish', () => check(t))
})
})
t.end()
})
t.test('flags', t => {
- const p = __dirname + '/flags'
+ const p = join(__dirname, '/flags')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'ok')
@@ -166,7 +166,7 @@ t.test('flags', t => {
})
t.test('mode', t => {
- const p = __dirname + '/mode'
+ const p = join(__dirname, '/mode')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'ok')
@@ -190,7 +190,7 @@ t.test('mode', t => {
})
t.test('write after end', t => {
- const p = __dirname + '/write-after-end'
+ const p = join(__dirname, '/write-after-end')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'ok')
@@ -220,7 +220,7 @@ t.test('write after end', t => {
})
t.test('fd', t => {
- const p = __dirname + '/fd'
+ const p = join(__dirname, '/fd')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), 'ok')
@@ -245,7 +245,7 @@ t.test('fd', t => {
})
t.test('empty write', t => {
- const p = __dirname + '/empty-write'
+ const p = join(__dirname, '/empty-write')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), '')
@@ -297,7 +297,7 @@ t.test('empty write', t => {
})
t.test('fail open', t => {
- const p = __dirname + '/fail-open'
+ const p = join(__dirname, '/fail-open')
const poop = new Error('poop')
t.teardown(mutateFS.fail('open', poop))
t.throws(_ => new fsm.WriteStreamSync(p), poop)
@@ -309,7 +309,7 @@ t.test('fail open', t => {
})
t.test('fail open, positioned write', t => {
- const p = __dirname + '/fail-open-positioned'
+ const p = join(__dirname, '/fail-open-positioned')
const poop = new Error('poop')
t.teardown(mutateFS.fail('open', poop))
t.throws(_ => new fsm.WriteStreamSync(p, { start: 2 }), poop)
@@ -321,7 +321,7 @@ t.test('fail open, positioned write', t => {
})
t.test('fail close', t => {
- const p = __dirname + '/fail-close'
+ const p = join(__dirname, '/fail-close')
const poop = new Error('poop')
t.teardown(mutateFS.fail('close', poop))
t.teardown(() => fs.unlinkSync(p))
@@ -338,7 +338,7 @@ t.test('fail write', t => {
const closeError = new Error('close error')
t.teardown(mutateFS.fail('close', closeError))
- const p = __dirname + '/fail-write'
+ const p = join(__dirname, '/fail-write')
const poop = new Error('poop')
t.teardown(mutateFS.fail('write', poop))
@@ -353,7 +353,7 @@ t.test('fail write', t => {
})
t.test('positioned write', t => {
- const p = __dirname + '/positioned-write'
+ const p = join(__dirname, '/positioned-write')
const write = Buffer.from('this is the data that is written')
const data = Buffer.allocUnsafe(256)
@@ -389,7 +389,7 @@ t.test('positioned write', t => {
})
t.test('positioned then unpositioned', t => {
- const p = __dirname + '/positioned-then-unpositioned'
+ const p = join(__dirname, '/positioned-then-unpositioned')
const write = Buffer.from('this is the data that is written')
const data = Buffer.allocUnsafe(256)
@@ -428,7 +428,7 @@ t.test('positioned then unpositioned', t => {
})
t.test('positioned then unpositioned at zero', t => {
- const p = __dirname + '/positioned-then-unpositioned'
+ const p = join(__dirname, '/positioned-then-unpositioned')
const write = Buffer.from('this is the data that is written')
const data = Buffer.allocUnsafe(256)
@@ -467,7 +467,7 @@ t.test('positioned then unpositioned at zero', t => {
})
t.test('fd, no autoClose', t => {
- const p = __dirname + '/fd-no-autoclose'
+ const p = join(__dirname, '/fd-no-autoclose')
const check = (t, fd) => {
fs.closeSync(fd)
@@ -493,7 +493,7 @@ t.test('fd, no autoClose', t => {
})
t.test('positioned, nonexistent file', t => {
- const p = __dirname + '/pos-noent'
+ const p = join(__dirname, '/pos-noent')
const check = t => {
t.equal(fs.readFileSync(p, 'utf8'), '\0\0asdf\0\0\0\0asdf')
@@ -513,9 +513,9 @@ t.test('positioned, nonexistent file', t => {
const w = new fsm.WriteStream(p, { start: 10 })
w.end('asdf')
w.on('close', _ => {
- const w = new fsm.WriteStream(p, { start: 2 })
- w.end('asdf')
- w.on('close', _ => check(t))
+ const w2 = new fsm.WriteStream(p, { start: 2 })
+ w2.end('asdf')
+ w2.on('close', () => check(t))
})
})