├── .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
├── README.md
├── SECURITY.md
├── lib
├── index.js
└── to-batch-syntax.js
├── package.json
├── release-please-config.json
├── tap-snapshots
├── test-basic.js-TAP.test.js
└── test
│ └── basic.js.test.cjs
└── test
├── 00-setup.js
├── basic.js
├── to-batch-syntax-tests.js
└── zz-cleanup.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 | permissions:
12 | contents: read
13 |
14 | jobs:
15 | audit:
16 | name: Audit Dependencies
17 | if: github.repository_owner == 'npm'
18 | runs-on: ubuntu-latest
19 | defaults:
20 | run:
21 | shell: bash
22 | steps:
23 | - name: Checkout
24 | uses: actions/checkout@v4
25 | - name: Setup Git User
26 | run: |
27 | git config --global user.email "npm-cli+bot@github.com"
28 | git config --global user.name "npm CLI robot"
29 | - name: Setup Node
30 | uses: actions/setup-node@v4
31 | id: node
32 | with:
33 | node-version: 22.x
34 | check-latest: contains('22.x', '.x')
35 | - name: Install Latest npm
36 | uses: ./.github/actions/install-latest-npm
37 | with:
38 | node: ${{ steps.node.outputs.node-version }}
39 | - name: Install Dependencies
40 | run: npm i --ignore-scripts --no-audit --no-fund --package-lock
41 | - name: Run Production Audit
42 | run: npm audit --omit=dev
43 | - name: Run Full Audit
44 | run: npm audit --audit-level=none
45 |
--------------------------------------------------------------------------------
/.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 | permissions:
22 | contents: read
23 | checks: write
24 |
25 | jobs:
26 | lint-all:
27 | name: Lint All
28 | if: github.repository_owner == 'npm'
29 | runs-on: ubuntu-latest
30 | defaults:
31 | run:
32 | shell: bash
33 | steps:
34 | - name: Checkout
35 | uses: actions/checkout@v4
36 | with:
37 | ref: ${{ inputs.ref }}
38 | - name: Setup Git User
39 | run: |
40 | git config --global user.email "npm-cli+bot@github.com"
41 | git config --global user.name "npm CLI robot"
42 | - name: Create Check
43 | id: create-check
44 | if: ${{ inputs.check-sha }}
45 | uses: ./.github/actions/create-check
46 | with:
47 | name: "Lint All"
48 | token: ${{ secrets.GITHUB_TOKEN }}
49 | sha: ${{ inputs.check-sha }}
50 | - name: Setup Node
51 | uses: actions/setup-node@v4
52 | id: node
53 | with:
54 | node-version: 22.x
55 | check-latest: contains('22.x', '.x')
56 | - name: Install Latest npm
57 | uses: ./.github/actions/install-latest-npm
58 | with:
59 | node: ${{ steps.node.outputs.node-version }}
60 | - name: Install Dependencies
61 | run: npm i --ignore-scripts --no-audit --no-fund
62 | - name: Lint
63 | run: npm run lint --ignore-scripts
64 | - name: Post Lint
65 | run: npm run postlint --ignore-scripts
66 | - name: Conclude Check
67 | uses: LouisBrunner/checks-action@v1.6.0
68 | if: steps.create-check.outputs.check-id && always()
69 | with:
70 | token: ${{ secrets.GITHUB_TOKEN }}
71 | conclusion: ${{ job.status }}
72 | check_id: ${{ steps.create-check.outputs.check-id }}
73 |
74 | test-all:
75 | name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }}
76 | if: github.repository_owner == 'npm'
77 | strategy:
78 | fail-fast: false
79 | matrix:
80 | platform:
81 | - name: Linux
82 | os: ubuntu-latest
83 | shell: bash
84 | - name: macOS
85 | os: macos-latest
86 | shell: bash
87 | - name: macOS
88 | os: macos-13
89 | shell: bash
90 | - name: Windows
91 | os: windows-latest
92 | shell: cmd
93 | node-version:
94 | - 18.17.0
95 | - 18.x
96 | - 20.5.0
97 | - 20.x
98 | - 22.x
99 | exclude:
100 | - platform: { name: macOS, os: macos-13, shell: bash }
101 | node-version: 18.17.0
102 | - platform: { name: macOS, os: macos-13, shell: bash }
103 | node-version: 18.x
104 | - platform: { name: macOS, os: macos-13, shell: bash }
105 | node-version: 20.5.0
106 | - platform: { name: macOS, os: macos-13, shell: bash }
107 | node-version: 20.x
108 | - platform: { name: macOS, os: macos-13, shell: bash }
109 | node-version: 22.x
110 | runs-on: ${{ matrix.platform.os }}
111 | defaults:
112 | run:
113 | shell: ${{ matrix.platform.shell }}
114 | steps:
115 | - name: Checkout
116 | uses: actions/checkout@v4
117 | with:
118 | ref: ${{ inputs.ref }}
119 | - name: Setup Git User
120 | run: |
121 | git config --global user.email "npm-cli+bot@github.com"
122 | git config --global user.name "npm CLI robot"
123 | - name: Create Check
124 | id: create-check
125 | if: ${{ inputs.check-sha }}
126 | uses: ./.github/actions/create-check
127 | with:
128 | name: "Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }}"
129 | token: ${{ secrets.GITHUB_TOKEN }}
130 | sha: ${{ inputs.check-sha }}
131 | - name: Setup Node
132 | uses: actions/setup-node@v4
133 | id: node
134 | with:
135 | node-version: ${{ matrix.node-version }}
136 | check-latest: contains(matrix.node-version, '.x')
137 | - name: Install Latest npm
138 | uses: ./.github/actions/install-latest-npm
139 | with:
140 | node: ${{ steps.node.outputs.node-version }}
141 | - name: Install Dependencies
142 | run: npm i --ignore-scripts --no-audit --no-fund
143 | - name: Add Problem Matcher
144 | run: echo "::add-matcher::.github/matchers/tap.json"
145 | - name: Test
146 | run: npm test --ignore-scripts
147 | - name: Conclude Check
148 | uses: LouisBrunner/checks-action@v1.6.0
149 | if: steps.create-check.outputs.check-id && always()
150 | with:
151 | token: ${{ secrets.GITHUB_TOKEN }}
152 | conclusion: ${{ job.status }}
153 | check_id: ${{ steps.create-check.outputs.check-id }}
154 |
--------------------------------------------------------------------------------
/.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 | permissions:
16 | contents: read
17 |
18 | jobs:
19 | lint:
20 | name: Lint
21 | if: github.repository_owner == 'npm'
22 | runs-on: ubuntu-latest
23 | defaults:
24 | run:
25 | shell: bash
26 | steps:
27 | - name: Checkout
28 | uses: actions/checkout@v4
29 | - name: Setup Git User
30 | run: |
31 | git config --global user.email "npm-cli+bot@github.com"
32 | git config --global user.name "npm CLI robot"
33 | - name: Setup Node
34 | uses: actions/setup-node@v4
35 | id: node
36 | with:
37 | node-version: 22.x
38 | check-latest: contains('22.x', '.x')
39 | - name: Install Latest npm
40 | uses: ./.github/actions/install-latest-npm
41 | with:
42 | node: ${{ steps.node.outputs.node-version }}
43 | - name: Install Dependencies
44 | run: npm i --ignore-scripts --no-audit --no-fund
45 | - name: Lint
46 | run: npm run lint --ignore-scripts
47 | - name: Post Lint
48 | run: npm run postlint --ignore-scripts
49 |
50 | test:
51 | name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }}
52 | if: github.repository_owner == 'npm'
53 | strategy:
54 | fail-fast: false
55 | matrix:
56 | platform:
57 | - name: Linux
58 | os: ubuntu-latest
59 | shell: bash
60 | - name: macOS
61 | os: macos-latest
62 | shell: bash
63 | - name: macOS
64 | os: macos-13
65 | shell: bash
66 | - name: Windows
67 | os: windows-latest
68 | shell: cmd
69 | node-version:
70 | - 18.17.0
71 | - 18.x
72 | - 20.5.0
73 | - 20.x
74 | - 22.x
75 | exclude:
76 | - platform: { name: macOS, os: macos-13, shell: bash }
77 | node-version: 18.17.0
78 | - platform: { name: macOS, os: macos-13, shell: bash }
79 | node-version: 18.x
80 | - platform: { name: macOS, os: macos-13, shell: bash }
81 | node-version: 20.5.0
82 | - platform: { name: macOS, os: macos-13, shell: bash }
83 | node-version: 20.x
84 | - platform: { name: macOS, os: macos-13, shell: bash }
85 | node-version: 22.x
86 | runs-on: ${{ matrix.platform.os }}
87 | defaults:
88 | run:
89 | shell: ${{ matrix.platform.shell }}
90 | steps:
91 | - name: Checkout
92 | uses: actions/checkout@v4
93 | - name: Setup Git User
94 | run: |
95 | git config --global user.email "npm-cli+bot@github.com"
96 | git config --global user.name "npm CLI robot"
97 | - name: Setup Node
98 | uses: actions/setup-node@v4
99 | id: node
100 | with:
101 | node-version: ${{ matrix.node-version }}
102 | check-latest: contains(matrix.node-version, '.x')
103 | - name: Install Latest npm
104 | uses: ./.github/actions/install-latest-npm
105 | with:
106 | node: ${{ steps.node.outputs.node-version }}
107 | - name: Install Dependencies
108 | run: npm i --ignore-scripts --no-audit --no-fund
109 | - name: Add Problem Matcher
110 | run: echo "::add-matcher::.github/matchers/tap.json"
111 | - name: Test
112 | run: npm test --ignore-scripts
113 |
--------------------------------------------------------------------------------
/.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 | permissions:
17 | contents: read
18 |
19 | jobs:
20 | analyze:
21 | name: Analyze
22 | runs-on: ubuntu-latest
23 | permissions:
24 | actions: read
25 | contents: read
26 | security-events: write
27 | steps:
28 | - name: Checkout
29 | uses: actions/checkout@v4
30 | - name: Setup Git User
31 | run: |
32 | git config --global user.email "npm-cli+bot@github.com"
33 | git config --global user.name "npm CLI robot"
34 | - name: Initialize CodeQL
35 | uses: github/codeql-action/init@v3
36 | with:
37 | languages: javascript
38 | - name: Perform CodeQL Analysis
39 | uses: github/codeql-action/analyze@v3
40 |
--------------------------------------------------------------------------------
/.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 | permissions:
14 | contents: read
15 |
16 | jobs:
17 | commitlint:
18 | name: Lint Commits
19 | if: github.repository_owner == 'npm'
20 | runs-on: ubuntu-latest
21 | defaults:
22 | run:
23 | shell: bash
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v4
27 | with:
28 | fetch-depth: 0
29 | - name: Setup Git User
30 | run: |
31 | git config --global user.email "npm-cli+bot@github.com"
32 | git config --global user.name "npm CLI robot"
33 | - name: Setup Node
34 | uses: actions/setup-node@v4
35 | id: node
36 | with:
37 | node-version: 22.x
38 | check-latest: contains('22.x', '.x')
39 | - name: Install Latest npm
40 | uses: ./.github/actions/install-latest-npm
41 | with:
42 | node: ${{ steps.node.outputs.node-version }}
43 | - name: Install Dependencies
44 | run: npm i --ignore-scripts --no-audit --no-fund
45 | - name: Run Commitlint on Commits
46 | id: commit
47 | continue-on-error: true
48 | run: npx --offline commitlint -V --from 'origin/${{ github.base_ref }}' --to ${{ github.event.pull_request.head.sha }}
49 | - name: Run Commitlint on PR Title
50 | if: steps.commit.outcome == 'failure'
51 | env:
52 | PR_TITLE: ${{ github.event.pull_request.title }}
53 | run: echo "$PR_TITLE" | npx --offline commitlint -V
54 |
--------------------------------------------------------------------------------
/.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 | permissions:
23 | contents: read
24 | id-token: write
25 |
26 | jobs:
27 | publish:
28 | name: Publish
29 | runs-on: ubuntu-latest
30 | defaults:
31 | run:
32 | shell: bash
33 | permissions:
34 | id-token: write
35 | steps:
36 | - name: Checkout
37 | uses: actions/checkout@v4
38 | with:
39 | ref: ${{ fromJSON(inputs.releases)[0].tagName }}
40 | - name: Setup Git User
41 | run: |
42 | git config --global user.email "npm-cli+bot@github.com"
43 | git config --global user.name "npm CLI robot"
44 | - name: Setup Node
45 | uses: actions/setup-node@v4
46 | id: node
47 | with:
48 | node-version: 22.x
49 | check-latest: contains('22.x', '.x')
50 | - name: Install Latest npm
51 | uses: ./.github/actions/install-latest-npm
52 | with:
53 | node: ${{ steps.node.outputs.node-version }}
54 | - name: Install Dependencies
55 | run: npm i --ignore-scripts --no-audit --no-fund
56 | - name: Set npm authToken
57 | run: npm config set '//registry.npmjs.org/:_authToken'=\${PUBLISH_TOKEN}
58 | - name: Publish
59 | env:
60 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
61 | RELEASES: ${{ inputs.releases }}
62 | run: |
63 | EXIT_CODE=0
64 |
65 | for release in $(echo $RELEASES | jq -r '.[] | @base64'); do
66 | PUBLISH_TAG=$(echo "$release" | base64 --decode | jq -r .publishTag)
67 | npm publish --provenance --tag="$PUBLISH_TAG"
68 | STATUS=$?
69 | if [[ "$STATUS" -eq 1 ]]; then
70 | EXIT_CODE=$STATUS
71 | fi
72 | done
73 |
74 | exit $EXIT_CODE
75 |
--------------------------------------------------------------------------------
/.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 | contents: read
248 | id-token: write
249 | secrets:
250 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
251 | with:
252 | releases: ${{ needs.release.outputs.releases }}
253 |
254 | post-release-integration:
255 | needs: [ release, release-integration, post-release ]
256 | name: Post Release Integration - Release
257 | if: github.repository_owner == 'npm' && needs.release.outputs.releases && always()
258 | runs-on: ubuntu-latest
259 | defaults:
260 | run:
261 | shell: bash
262 | steps:
263 | - name: Get Post Release Conclusion
264 | id: conclusion
265 | run: |
266 | if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then
267 | result="x"
268 | elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
269 | result="heavy_multiplication_x"
270 | else
271 | result="white_check_mark"
272 | fi
273 | echo "result=$result" >> $GITHUB_OUTPUT
274 | - name: Find Release PR Comment
275 | uses: peter-evans/find-comment@v2
276 | id: found-comment
277 | with:
278 | issue-number: ${{ fromJSON(needs.release.outputs.releases)[0].prNumber }}
279 | comment-author: 'github-actions[bot]'
280 | body-includes: '## Release Workflow'
281 | - name: Create Release PR Comment Text
282 | id: comment-text
283 | if: steps.found-comment.outputs.comment-id
284 | uses: actions/github-script@v7
285 | env:
286 | RESULT: ${{ steps.conclusion.outputs.result }}
287 | BODY: ${{ steps.found-comment.outputs.comment-body }}
288 | with:
289 | result-encoding: string
290 | script: |
291 | const { RESULT, BODY } = process.env
292 | const body = [BODY.replace(/(Workflow run: :)[a-z_]+(:)/, `$1${RESULT}$2`)]
293 | if (RESULT !== 'white_check_mark') {
294 | body.push(':rotating_light::rotating_light::rotating_light:')
295 | body.push([
296 | '@npm/cli-team: The post-release workflow failed for this release.',
297 | 'Manual steps may need to be taken after examining the workflow output.'
298 | ].join(' '))
299 | body.push(':rotating_light::rotating_light::rotating_light:')
300 | }
301 | return body.join('\n\n').trim()
302 | - name: Update Release PR Comment
303 | if: steps.comment-text.outputs.result
304 | uses: peter-evans/create-or-update-comment@v3
305 | with:
306 | comment-id: ${{ steps.found-comment.outputs.comment-id }}
307 | body: ${{ steps.comment-text.outputs.result }}
308 | edit-mode: 'replace'
309 |
--------------------------------------------------------------------------------
/.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 | !/.eslint.config.js
9 | !/.eslintrc.js
10 | !/.eslintrc.local.*
11 | !/.git-blame-ignore-revs
12 | !/.github/
13 | !/.gitignore
14 | !/.npmrc
15 | !/.prettierignore
16 | !/.prettierrc.js
17 | !/.release-please-manifest.json
18 | !/bin/
19 | !/CHANGELOG*
20 | !/CODE_OF_CONDUCT.md
21 | !/CONTRIBUTING.md
22 | !/docs/
23 | !/lib/
24 | !/LICENSE*
25 | !/map.js
26 | !/package.json
27 | !/README*
28 | !/release-please-config.json
29 | !/scripts/
30 | !/SECURITY.md
31 | !/tap-snapshots/
32 | !/test/
33 | !/tsconfig.json
34 | tap-testdir*/
35 |
--------------------------------------------------------------------------------
/.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 | ".": "7.0.0"
3 | }
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [7.0.0](https://github.com/npm/cmd-shim/compare/v6.0.3...v7.0.0) (2024-08-26)
4 |
5 | ### ⚠️ BREAKING CHANGES
6 |
7 | * `cmd-shim` now supports node `^18.17.0 || >=20.5.0`
8 |
9 | ### Bug Fixes
10 |
11 | * [`aaf6016`](https://github.com/npm/cmd-shim/commit/aaf601687a131bec7eb94ff06d8fb417f95eed6e) [#154](https://github.com/npm/cmd-shim/pull/154) align to npm 10 node engine range (@hashtagchris)
12 |
13 | ### Chores
14 |
15 | * [`926af07`](https://github.com/npm/cmd-shim/commit/926af0785a59e512d3ea9316b58f98bbe9fb2a88) [#154](https://github.com/npm/cmd-shim/pull/154) run template-oss-apply (@hashtagchris)
16 | * [`7c154f3`](https://github.com/npm/cmd-shim/commit/7c154f30af2c4e52d34320d044e1201017cbcea2) [#151](https://github.com/npm/cmd-shim/pull/151) postinstall for dependabot template-oss PR (@hashtagchris)
17 | * [`21178ef`](https://github.com/npm/cmd-shim/commit/21178ef7fc0d087c3071451547e5c635cc19271e) [#151](https://github.com/npm/cmd-shim/pull/151) bump @npmcli/template-oss from 4.22.0 to 4.23.1 (@dependabot[bot])
18 |
19 | ## [6.0.3](https://github.com/npm/cmd-shim/compare/v6.0.2...v6.0.3) (2024-05-04)
20 |
21 | ### Bug Fixes
22 |
23 | * [`dbe91b4`](https://github.com/npm/cmd-shim/commit/dbe91b4433990e0566903b29a2a17d81ded5890b) [#140](https://github.com/npm/cmd-shim/pull/140) linting: no-unused-vars (@lukekarrys)
24 |
25 | ### Documentation
26 |
27 | * [`5598b4b`](https://github.com/npm/cmd-shim/commit/5598b4b5d04d42201543dc67b459f0a7db78c211) [#137](https://github.com/npm/cmd-shim/pull/137) readme: fix broken badge URLs (#137) (@10xLaCroixDrinker)
28 |
29 | ### Chores
30 |
31 | * [`3140bb1`](https://github.com/npm/cmd-shim/commit/3140bb131f84ac8fc284f1120c5a963621cd001f) [#140](https://github.com/npm/cmd-shim/pull/140) bump @npmcli/template-oss to 4.22.0 (@lukekarrys)
32 | * [`c944f6b`](https://github.com/npm/cmd-shim/commit/c944f6bb60f10b0c2aa803427233a7c76169a8c1) [#140](https://github.com/npm/cmd-shim/pull/140) postinstall for dependabot template-oss PR (@lukekarrys)
33 | * [`fa3f56b`](https://github.com/npm/cmd-shim/commit/fa3f56b3ab022523f59cae4081912a8b535ac234) [#139](https://github.com/npm/cmd-shim/pull/139) bump @npmcli/template-oss from 4.21.3 to 4.21.4 (@dependabot[bot])
34 |
35 | ## [6.0.2](https://github.com/npm/cmd-shim/compare/v6.0.1...v6.0.2) (2023-10-18)
36 |
37 | ### Bug Fixes
38 |
39 | * [`3bdb518`](https://github.com/npm/cmd-shim/commit/3bdb518db21ec6ae64cda74405c7025ee76ccd76) [#117](https://github.com/npm/cmd-shim/pull/117) don't assume cygpath is available (#117) (@davhdavh)
40 |
41 | ## [6.0.1](https://github.com/npm/cmd-shim/compare/v6.0.0...v6.0.1) (2022-12-13)
42 |
43 | ### Bug Fixes
44 |
45 | * [`a32b3a0`](https://github.com/npm/cmd-shim/commit/a32b3a06615ed60afaa0441015fb1a456b6be488) [#96](https://github.com/npm/cmd-shim/pull/96) drop the -S flag from env (#96) (@nlf, @yeldiRium)
46 |
47 | ## [6.0.0](https://github.com/npm/cmd-shim/compare/v5.0.0...v6.0.0) (2022-10-11)
48 |
49 | ### ⚠️ BREAKING CHANGES
50 |
51 | * this module will no longer attempt to alter file ownership
52 | * `cmd-shim` is now compatible with the following semver range for node: `^14.17.0 || ^16.13.0 || >=18.0.0`
53 |
54 | ### Features
55 |
56 | * [`ef99e1c`](https://github.com/npm/cmd-shim/commit/ef99e1cb605c2c8c35d40d8aa771f8060540ac91) [#88](https://github.com/npm/cmd-shim/pull/88) remove ownership changing features (#88) (@nlf)
57 | * [`d5881e8`](https://github.com/npm/cmd-shim/commit/d5881e893bd5a2405ecd6cc53bcb862b43665860) [#82](https://github.com/npm/cmd-shim/pull/82) postinstall for dependabot template-oss PR (@lukekarrys)
58 |
59 | ## [5.0.0](https://github.com/npm/cmd-shim/compare/v4.1.0...v5.0.0) (2022-04-05)
60 |
61 |
62 | ### ⚠ BREAKING CHANGES
63 |
64 | * this drops support for node 10 and non-LTS versions of node 12 and node 14
65 |
66 | ### Bug Fixes
67 |
68 | * replace deprecated String.prototype.substr() ([#59](https://github.com/npm/cmd-shim/issues/59)) ([383d7e9](https://github.com/npm/cmd-shim/commit/383d7e954b72b76d88fad74510204c8ed12a37c1))
69 | * safer regex ([470678a](https://github.com/npm/cmd-shim/commit/470678a5bfbdacabda8327a3e181bbf0cbcaba12))
70 |
71 |
72 | ### Dependencies
73 |
74 | * @npmcli/template-oss@3.2.2 ([dfb091d](https://github.com/npm/cmd-shim/commit/dfb091de0d61fa83ee1a32ceb7810565bf7ed31b))
75 |
--------------------------------------------------------------------------------
/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:
--------------------------------------------------------------------------------
1 | The ISC License
2 |
3 | Copyright (c) npm, Inc. and Contributors
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cmd-shim
2 |
3 | The cmd-shim used in npm to create executable scripts on Windows,
4 | since symlinks are not suitable for this purpose there.
5 |
6 | On Unix systems, you should use a symbolic link instead.
7 |
8 | [](https://github.com/npm/cmd-shim)
9 | [](https://libraries.io/npm/cmd-shim)
10 | [](https://www.npmjs.com/package/cmd-shim)
11 |
12 | ## Installation
13 |
14 | ```
15 | npm install cmd-shim
16 | ```
17 |
18 | ## API
19 |
20 | ### cmdShim(from, to) -> Promise
21 |
22 | Create a cmd shim at `to` for the command line program at `from`.
23 | e.g.
24 |
25 | ```javascript
26 | var cmdShim = require('cmd-shim');
27 | cmdShim(__dirname + '/cli.js', '/usr/bin/command-name').then(() => {
28 | // shims are created!
29 | })
30 | ```
31 |
32 | ### cmdShim.ifExists(from, to) -> Promise
33 |
34 | The same as above, but will just continue if the file does not exist.
35 |
--------------------------------------------------------------------------------
/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/index.js:
--------------------------------------------------------------------------------
1 | // On windows, create a .cmd file.
2 | // Read the #! in the file to see what it uses. The vast majority
3 | // of the time, this will be either:
4 | // "#!/usr/bin/env "
5 | // or:
6 | // "#! "
7 | //
8 | // Write a binroot/pkg.bin + ".cmd" file that has this line in it:
9 | // @ %dp0% %*
10 |
11 | const {
12 | chmod,
13 | mkdir,
14 | readFile,
15 | stat,
16 | unlink,
17 | writeFile,
18 | } = require('fs/promises')
19 |
20 | const { dirname, relative } = require('path')
21 | const toBatchSyntax = require('./to-batch-syntax')
22 | // linting disabled because this regex is really long
23 | // eslint-disable-next-line max-len
24 | const shebangExpr = /^#!\s*(?:\/usr\/bin\/env\s+(?:-S\s+)?((?:[^ \t=]+=[^ \t=]+\s+)*))?([^ \t]+)(.*)$/
25 |
26 | const cmdShimIfExists = (from, to) =>
27 | stat(from).then(() => cmdShim(from, to), () => {})
28 |
29 | // Try to unlink, but ignore errors.
30 | // Any problems will surface later.
31 | const rm = path => unlink(path).catch(() => {})
32 |
33 | const cmdShim = (from, to) =>
34 | stat(from).then(() => cmdShim_(from, to))
35 |
36 | const cmdShim_ = (from, to) => Promise.all([
37 | rm(to),
38 | rm(to + '.cmd'),
39 | rm(to + '.ps1'),
40 | ]).then(() => writeShim(from, to))
41 |
42 | const writeShim = (from, to) =>
43 | // make a cmd file and a sh script
44 | // First, check if the bin is a #! of some sort.
45 | // If not, then assume it's something that'll be compiled, or some other
46 | // sort of script, and just call it directly.
47 | mkdir(dirname(to), { recursive: true })
48 | .then(() => readFile(from, 'utf8'))
49 | .then(data => {
50 | const firstLine = data.trim().split(/\r*\n/)[0]
51 | const shebang = firstLine.match(shebangExpr)
52 | if (!shebang) {
53 | return writeShim_(from, to)
54 | }
55 | const vars = shebang[1] || ''
56 | const prog = shebang[2]
57 | const args = shebang[3] || ''
58 | return writeShim_(from, to, prog, args, vars)
59 | }, () => writeShim_(from, to))
60 |
61 | const writeShim_ = (from, to, prog, args, variables) => {
62 | let shTarget = relative(dirname(to), from)
63 | let target = shTarget.split('/').join('\\')
64 | let longProg
65 | let shProg = prog && prog.split('\\').join('/')
66 | let shLongProg
67 | let pwshProg = shProg && `"${shProg}$exe"`
68 | let pwshLongProg
69 | shTarget = shTarget.split('\\').join('/')
70 | args = args || ''
71 | variables = variables || ''
72 | if (!prog) {
73 | prog = `"%dp0%\\${target}"`
74 | shProg = `"$basedir/${shTarget}"`
75 | pwshProg = shProg
76 | args = ''
77 | target = ''
78 | shTarget = ''
79 | } else {
80 | longProg = `"%dp0%\\${prog}.exe"`
81 | shLongProg = `"$basedir/${prog}"`
82 | pwshLongProg = `"$basedir/${prog}$exe"`
83 | target = `"%dp0%\\${target}"`
84 | shTarget = `"$basedir/${shTarget}"`
85 | }
86 |
87 | // Subroutine trick to fix https://github.com/npm/cmd-shim/issues/10
88 | // and https://github.com/npm/cli/issues/969
89 | const head = '@ECHO off\r\n' +
90 | 'GOTO start\r\n' +
91 | ':find_dp0\r\n' +
92 | 'SET dp0=%~dp0\r\n' +
93 | 'EXIT /b\r\n' +
94 | ':start\r\n' +
95 | 'SETLOCAL\r\n' +
96 | 'CALL :find_dp0\r\n'
97 |
98 | let cmd
99 | if (longProg) {
100 | shLongProg = shLongProg.trim()
101 | args = args.trim()
102 | const variablesBatch = toBatchSyntax.convertToSetCommands(variables)
103 | cmd = head
104 | + variablesBatch
105 | + '\r\n'
106 | + `IF EXIST ${longProg} (\r\n`
107 | + ` SET "_prog=${longProg.replace(/(^")|("$)/g, '')}"\r\n`
108 | + ') ELSE (\r\n'
109 | + ` SET "_prog=${prog.replace(/(^")|("$)/g, '')}"\r\n`
110 | + ' SET PATHEXT=%PATHEXT:;.JS;=;%\r\n'
111 | + ')\r\n'
112 | + '\r\n'
113 | // prevent "Terminate Batch Job? (Y/n)" message
114 | // https://github.com/npm/cli/issues/969#issuecomment-737496588
115 | + 'endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & '
116 | + `"%_prog%" ${args} ${target} %*\r\n`
117 | } else {
118 | cmd = `${head}${prog} ${args} ${target} %*\r\n`
119 | }
120 |
121 | // #!/bin/sh
122 | // basedir=`dirname "$0"`
123 | //
124 | // case `uname` in
125 | // *CYGWIN*|*MINGW*|*MSYS*)
126 | // if command -v cygpath > /dev/null 2>&1; then
127 | // basedir=`cygpath -w "$basedir"`
128 | // fi
129 | // ;;
130 | // esac
131 | //
132 | // if [ -x "$basedir/node.exe" ]; then
133 | // exec "$basedir/node.exe" "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
134 | // else
135 | // exec node "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
136 | // fi
137 |
138 | let sh = '#!/bin/sh\n'
139 |
140 | sh = sh
141 | + `basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")\n`
142 | + '\n'
143 | + 'case `uname` in\n'
144 | + ' *CYGWIN*|*MINGW*|*MSYS*)\n'
145 | + ' if command -v cygpath > /dev/null 2>&1; then\n'
146 | + ' basedir=`cygpath -w "$basedir"`\n'
147 | + ' fi\n'
148 | + ' ;;\n'
149 | + 'esac\n'
150 | + '\n'
151 |
152 | if (shLongProg) {
153 | sh = sh
154 | + `if [ -x ${shLongProg} ]; then\n`
155 | + ` exec ${variables}${shLongProg} ${args} ${shTarget} "$@"\n`
156 | + 'else \n'
157 | + ` exec ${variables}${shProg} ${args} ${shTarget} "$@"\n`
158 | + 'fi\n'
159 | } else {
160 | sh = sh
161 | + `exec ${shProg} ${args} ${shTarget} "$@"\n`
162 | }
163 |
164 | // #!/usr/bin/env pwsh
165 | // $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
166 | //
167 | // $ret=0
168 | // $exe = ""
169 | // if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
170 | // # Fix case when both the Windows and Linux builds of Node
171 | // # are installed in the same directory
172 | // $exe = ".exe"
173 | // }
174 | // if (Test-Path "$basedir/node") {
175 | // # Suport pipeline input
176 | // if ($MyInvocation.ExpectingInput) {
177 | // input | & "$basedir/node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
178 | // } else {
179 | // & "$basedir/node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
180 | // }
181 | // $ret=$LASTEXITCODE
182 | // } else {
183 | // # Support pipeline input
184 | // if ($MyInvocation.ExpectingInput) {
185 | // $input | & "node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
186 | // } else {
187 | // & "node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
188 | // }
189 | // $ret=$LASTEXITCODE
190 | // }
191 | // exit $ret
192 | let pwsh = '#!/usr/bin/env pwsh\n'
193 | + '$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n'
194 | + '\n'
195 | + '$exe=""\n'
196 | + 'if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {\n'
197 | + ' # Fix case when both the Windows and Linux builds of Node\n'
198 | + ' # are installed in the same directory\n'
199 | + ' $exe=".exe"\n'
200 | + '}\n'
201 | if (shLongProg) {
202 | pwsh = pwsh
203 | + '$ret=0\n'
204 | + `if (Test-Path ${pwshLongProg}) {\n`
205 | + ' # Support pipeline input\n'
206 | + ' if ($MyInvocation.ExpectingInput) {\n'
207 | + ` $input | & ${pwshLongProg} ${args} ${shTarget} $args\n`
208 | + ' } else {\n'
209 | + ` & ${pwshLongProg} ${args} ${shTarget} $args\n`
210 | + ' }\n'
211 | + ' $ret=$LASTEXITCODE\n'
212 | + '} else {\n'
213 | + ' # Support pipeline input\n'
214 | + ' if ($MyInvocation.ExpectingInput) {\n'
215 | + ` $input | & ${pwshProg} ${args} ${shTarget} $args\n`
216 | + ' } else {\n'
217 | + ` & ${pwshProg} ${args} ${shTarget} $args\n`
218 | + ' }\n'
219 | + ' $ret=$LASTEXITCODE\n'
220 | + '}\n'
221 | + 'exit $ret\n'
222 | } else {
223 | pwsh = pwsh
224 | + '# Support pipeline input\n'
225 | + 'if ($MyInvocation.ExpectingInput) {\n'
226 | + ` $input | & ${pwshProg} ${args} ${shTarget} $args\n`
227 | + '} else {\n'
228 | + ` & ${pwshProg} ${args} ${shTarget} $args\n`
229 | + '}\n'
230 | + 'exit $LASTEXITCODE\n'
231 | }
232 |
233 | return Promise.all([
234 | writeFile(to + '.ps1', pwsh, 'utf8'),
235 | writeFile(to + '.cmd', cmd, 'utf8'),
236 | writeFile(to, sh, 'utf8'),
237 | ]).then(() => chmodShim(to))
238 | }
239 |
240 | const chmodShim = to => Promise.all([
241 | chmod(to, 0o755),
242 | chmod(to + '.cmd', 0o755),
243 | chmod(to + '.ps1', 0o755),
244 | ])
245 |
246 | module.exports = cmdShim
247 | cmdShim.ifExists = cmdShimIfExists
248 |
--------------------------------------------------------------------------------
/lib/to-batch-syntax.js:
--------------------------------------------------------------------------------
1 | exports.replaceDollarWithPercentPair = replaceDollarWithPercentPair
2 | exports.convertToSetCommand = convertToSetCommand
3 | exports.convertToSetCommands = convertToSetCommands
4 |
5 | function convertToSetCommand (key, value) {
6 | var line = ''
7 | key = key || ''
8 | key = key.trim()
9 | value = value || ''
10 | value = value.trim()
11 | if (key && value && value.length > 0) {
12 | line = '@SET ' + key + '=' + replaceDollarWithPercentPair(value) + '\r\n'
13 | }
14 | return line
15 | }
16 |
17 | function extractVariableValuePairs (declarations) {
18 | var pairs = {}
19 | declarations.map(function (declaration) {
20 | var split = declaration.split('=')
21 | pairs[split[0]] = split[1]
22 | })
23 | return pairs
24 | }
25 |
26 | function convertToSetCommands (variableString) {
27 | var variableValuePairs = extractVariableValuePairs(variableString.split(' '))
28 | var variableDeclarationsAsBatch = ''
29 | Object.keys(variableValuePairs).forEach(function (key) {
30 | variableDeclarationsAsBatch += convertToSetCommand(key, variableValuePairs[key])
31 | })
32 | return variableDeclarationsAsBatch
33 | }
34 |
35 | function replaceDollarWithPercentPair (value) {
36 | var dollarExpressions = /\$\{?([^$@#?\- \t{}:]+)\}?/g
37 | var result = ''
38 | var startIndex = 0
39 | do {
40 | var match = dollarExpressions.exec(value)
41 | if (match) {
42 | var betweenMatches = value.substring(startIndex, match.index) || ''
43 | result += betweenMatches + '%' + match[1] + '%'
44 | startIndex = dollarExpressions.lastIndex
45 | }
46 | } while (dollarExpressions.lastIndex > 0)
47 | result += value.slice(startIndex)
48 | return result
49 | }
50 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cmd-shim",
3 | "version": "7.0.0",
4 | "description": "Used in npm for command line application support",
5 | "scripts": {
6 | "test": "tap",
7 | "snap": "tap",
8 | "lint": "npm run eslint",
9 | "postlint": "template-oss-check",
10 | "template-oss-apply": "template-oss-apply --force",
11 | "lintfix": "npm run eslint -- --fix",
12 | "posttest": "npm run lint",
13 | "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/npm/cmd-shim.git"
18 | },
19 | "license": "ISC",
20 | "devDependencies": {
21 | "@npmcli/eslint-config": "^5.0.0",
22 | "@npmcli/template-oss": "4.24.3",
23 | "tap": "^16.0.1"
24 | },
25 | "files": [
26 | "bin/",
27 | "lib/"
28 | ],
29 | "main": "lib/index.js",
30 | "tap": {
31 | "before": "test/00-setup.js",
32 | "after": "test/zz-cleanup.js",
33 | "check-coverage": true,
34 | "nyc-arg": [
35 | "--exclude",
36 | "tap-snapshots/**"
37 | ]
38 | },
39 | "engines": {
40 | "node": "^18.17.0 || >=20.5.0"
41 | },
42 | "author": "GitHub Inc.",
43 | "templateOSS": {
44 | "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
45 | "version": "4.24.3",
46 | "publish": true
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/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.0"
37 | }
38 |
--------------------------------------------------------------------------------
/tap-snapshots/test-basic.js-TAP.test.js:
--------------------------------------------------------------------------------
1 | /* IMPORTANT
2 | * This snapshot file is auto-generated, but designed for humans.
3 | * It should be checked into source control and tracked carefully.
4 | * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
5 | * Make sure to inspect the output below. Do not ignore changes!
6 | */
7 | 'use strict'
8 | exports[`test/basic.js TAP env shebang > cmd 1`] = `
9 | @ECHO off\\r
10 | GOTO start\\r
11 | :find_dp0\\r
12 | SET dp0=%~dp0\\r
13 | EXIT /b\\r
14 | :start\\r
15 | SETLOCAL\\r
16 | CALL :find_dp0\\r
17 | \\r
18 | IF EXIST "%dp0%\\node.exe" (\\r
19 | SET "_prog=%dp0%\\node.exe"\\r
20 | ) ELSE (\\r
21 | SET "_prog=node"\\r
22 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
23 | )\\r
24 | \\r
25 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\from.env" %*\\r
26 |
27 | `
28 |
29 | exports[`test/basic.js TAP env shebang > ps1 1`] = `
30 | #!/usr/bin/env pwsh
31 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
32 |
33 | $exe=""
34 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
35 | # Fix case when both the Windows and Linux builds of Node
36 | # are installed in the same directory
37 | $exe=".exe"
38 | }
39 | $ret=0
40 | if (Test-Path "$basedir/node$exe") {
41 | # Support pipeline input
42 | if ($MyInvocation.ExpectingInput) {
43 | $input | & "$basedir/node$exe" "$basedir/from.env" $args
44 | } else {
45 | & "$basedir/node$exe" "$basedir/from.env" $args
46 | }
47 | $ret=$LASTEXITCODE
48 | } else {
49 | # Support pipeline input
50 | if ($MyInvocation.ExpectingInput) {
51 | $input | & "node$exe" "$basedir/from.env" $args
52 | } else {
53 | & "node$exe" "$basedir/from.env" $args
54 | }
55 | $ret=$LASTEXITCODE
56 | }
57 | exit $ret
58 |
59 | `
60 |
61 | exports[`test/basic.js TAP env shebang > shell 1`] = `
62 | #!/bin/sh
63 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
64 |
65 | case \`uname\` in
66 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
67 | esac
68 |
69 | if [ -x "$basedir/node" ]; then
70 | exec "$basedir/node" "$basedir/from.env" "$@"
71 | else
72 | exec node "$basedir/from.env" "$@"
73 | fi
74 |
75 | `
76 |
77 | exports[`test/basic.js TAP env shebang with args > cmd 1`] = `
78 | @ECHO off\\r
79 | GOTO start\\r
80 | :find_dp0\\r
81 | SET dp0=%~dp0\\r
82 | EXIT /b\\r
83 | :start\\r
84 | SETLOCAL\\r
85 | CALL :find_dp0\\r
86 | \\r
87 | IF EXIST "%dp0%\\node.exe" (\\r
88 | SET "_prog=%dp0%\\node.exe"\\r
89 | ) ELSE (\\r
90 | SET "_prog=node"\\r
91 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
92 | )\\r
93 | \\r
94 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" --expose_gc "%dp0%\\from.env.args" %*\\r
95 |
96 | `
97 |
98 | exports[`test/basic.js TAP env shebang with args > ps1 1`] = `
99 | #!/usr/bin/env pwsh
100 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
101 |
102 | $exe=""
103 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
104 | # Fix case when both the Windows and Linux builds of Node
105 | # are installed in the same directory
106 | $exe=".exe"
107 | }
108 | $ret=0
109 | if (Test-Path "$basedir/node$exe") {
110 | # Support pipeline input
111 | if ($MyInvocation.ExpectingInput) {
112 | $input | & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args
113 | } else {
114 | & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args
115 | }
116 | $ret=$LASTEXITCODE
117 | } else {
118 | # Support pipeline input
119 | if ($MyInvocation.ExpectingInput) {
120 | $input | & "node$exe" --expose_gc "$basedir/from.env.args" $args
121 | } else {
122 | & "node$exe" --expose_gc "$basedir/from.env.args" $args
123 | }
124 | $ret=$LASTEXITCODE
125 | }
126 | exit $ret
127 |
128 | `
129 |
130 | exports[`test/basic.js TAP env shebang with args > shell 1`] = `
131 | #!/bin/sh
132 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
133 |
134 | case \`uname\` in
135 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
136 | esac
137 |
138 | if [ -x "$basedir/node" ]; then
139 | exec "$basedir/node" --expose_gc "$basedir/from.env.args" "$@"
140 | else
141 | exec node --expose_gc "$basedir/from.env.args" "$@"
142 | fi
143 |
144 | `
145 |
146 | exports[`test/basic.js TAP env shebang with variables > cmd 1`] = `
147 | @ECHO off\\r
148 | GOTO start\\r
149 | :find_dp0\\r
150 | SET dp0=%~dp0\\r
151 | EXIT /b\\r
152 | :start\\r
153 | SETLOCAL\\r
154 | CALL :find_dp0\\r
155 | @SET NODE_PATH=./lib:%NODE_PATH%\\r
156 | \\r
157 | IF EXIST "%dp0%\\node.exe" (\\r
158 | SET "_prog=%dp0%\\node.exe"\\r
159 | ) ELSE (\\r
160 | SET "_prog=node"\\r
161 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
162 | )\\r
163 | \\r
164 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\from.env.variables" %*\\r
165 |
166 | `
167 |
168 | exports[`test/basic.js TAP env shebang with variables > ps1 1`] = `
169 | #!/usr/bin/env pwsh
170 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
171 |
172 | $exe=""
173 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
174 | # Fix case when both the Windows and Linux builds of Node
175 | # are installed in the same directory
176 | $exe=".exe"
177 | }
178 | $ret=0
179 | if (Test-Path "$basedir/node$exe") {
180 | # Support pipeline input
181 | if ($MyInvocation.ExpectingInput) {
182 | $input | & "$basedir/node$exe" "$basedir/from.env.variables" $args
183 | } else {
184 | & "$basedir/node$exe" "$basedir/from.env.variables" $args
185 | }
186 | $ret=$LASTEXITCODE
187 | } else {
188 | # Support pipeline input
189 | if ($MyInvocation.ExpectingInput) {
190 | $input | & "node$exe" "$basedir/from.env.variables" $args
191 | } else {
192 | & "node$exe" "$basedir/from.env.variables" $args
193 | }
194 | $ret=$LASTEXITCODE
195 | }
196 | exit $ret
197 |
198 | `
199 |
200 | exports[`test/basic.js TAP env shebang with variables > shell 1`] = `
201 | #!/bin/sh
202 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
203 |
204 | case \`uname\` in
205 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
206 | esac
207 |
208 | if [ -x "$basedir/node" ]; then
209 | exec NODE_PATH=./lib:$NODE_PATH "$basedir/node" "$basedir/from.env.variables" "$@"
210 | else
211 | exec NODE_PATH=./lib:$NODE_PATH node "$basedir/from.env.variables" "$@"
212 | fi
213 |
214 | `
215 |
216 | exports[`test/basic.js TAP explicit shebang > cmd 1`] = `
217 | @ECHO off\\r
218 | GOTO start\\r
219 | :find_dp0\\r
220 | SET dp0=%~dp0\\r
221 | EXIT /b\\r
222 | :start\\r
223 | SETLOCAL\\r
224 | CALL :find_dp0\\r
225 | \\r
226 | IF EXIST "%dp0%\\/usr/bin/sh.exe" (\\r
227 | SET "_prog=%dp0%\\/usr/bin/sh.exe"\\r
228 | ) ELSE (\\r
229 | SET "_prog=/usr/bin/sh"\\r
230 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
231 | )\\r
232 | \\r
233 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\from.sh" %*\\r
234 |
235 | `
236 |
237 | exports[`test/basic.js TAP explicit shebang > ps1 1`] = `
238 | #!/usr/bin/env pwsh
239 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
240 |
241 | $exe=""
242 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
243 | # Fix case when both the Windows and Linux builds of Node
244 | # are installed in the same directory
245 | $exe=".exe"
246 | }
247 | $ret=0
248 | if (Test-Path "$basedir//usr/bin/sh$exe") {
249 | # Support pipeline input
250 | if ($MyInvocation.ExpectingInput) {
251 | $input | & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args
252 | } else {
253 | & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args
254 | }
255 | $ret=$LASTEXITCODE
256 | } else {
257 | # Support pipeline input
258 | if ($MyInvocation.ExpectingInput) {
259 | $input | & "/usr/bin/sh$exe" "$basedir/from.sh" $args
260 | } else {
261 | & "/usr/bin/sh$exe" "$basedir/from.sh" $args
262 | }
263 | $ret=$LASTEXITCODE
264 | }
265 | exit $ret
266 |
267 | `
268 |
269 | exports[`test/basic.js TAP explicit shebang > shell 1`] = `
270 | #!/bin/sh
271 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
272 |
273 | case \`uname\` in
274 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
275 | esac
276 |
277 | if [ -x "$basedir//usr/bin/sh" ]; then
278 | exec "$basedir//usr/bin/sh" "$basedir/from.sh" "$@"
279 | else
280 | exec /usr/bin/sh "$basedir/from.sh" "$@"
281 | fi
282 |
283 | `
284 |
285 | exports[`test/basic.js TAP explicit shebang with args > cmd 1`] = `
286 | @ECHO off\\r
287 | GOTO start\\r
288 | :find_dp0\\r
289 | SET dp0=%~dp0\\r
290 | EXIT /b\\r
291 | :start\\r
292 | SETLOCAL\\r
293 | CALL :find_dp0\\r
294 | \\r
295 | IF EXIST "%dp0%\\/usr/bin/sh.exe" (\\r
296 | SET "_prog=%dp0%\\/usr/bin/sh.exe"\\r
297 | ) ELSE (\\r
298 | SET "_prog=/usr/bin/sh"\\r
299 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
300 | )\\r
301 | \\r
302 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" -x "%dp0%\\from.sh.args" %*\\r
303 |
304 | `
305 |
306 | exports[`test/basic.js TAP explicit shebang with args > ps1 1`] = `
307 | #!/usr/bin/env pwsh
308 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
309 |
310 | $exe=""
311 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
312 | # Fix case when both the Windows and Linux builds of Node
313 | # are installed in the same directory
314 | $exe=".exe"
315 | }
316 | $ret=0
317 | if (Test-Path "$basedir//usr/bin/sh$exe") {
318 | # Support pipeline input
319 | if ($MyInvocation.ExpectingInput) {
320 | $input | & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
321 | } else {
322 | & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
323 | }
324 | $ret=$LASTEXITCODE
325 | } else {
326 | # Support pipeline input
327 | if ($MyInvocation.ExpectingInput) {
328 | $input | & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
329 | } else {
330 | & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
331 | }
332 | $ret=$LASTEXITCODE
333 | }
334 | exit $ret
335 |
336 | `
337 |
338 | exports[`test/basic.js TAP explicit shebang with args > shell 1`] = `
339 | #!/bin/sh
340 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
341 |
342 | case \`uname\` in
343 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
344 | esac
345 |
346 | if [ -x "$basedir//usr/bin/sh" ]; then
347 | exec "$basedir//usr/bin/sh" -x "$basedir/from.sh.args" "$@"
348 | else
349 | exec /usr/bin/sh -x "$basedir/from.sh.args" "$@"
350 | fi
351 |
352 | `
353 |
354 | exports[`test/basic.js TAP if exists (it does exist) > cmd 1`] = `
355 | @ECHO off\\r
356 | GOTO start\\r
357 | :find_dp0\\r
358 | SET dp0=%~dp0\\r
359 | EXIT /b\\r
360 | :start\\r
361 | SETLOCAL\\r
362 | CALL :find_dp0\\r
363 | "%dp0%\\from.exe" %*\\r
364 |
365 | `
366 |
367 | exports[`test/basic.js TAP if exists (it does exist) > ps1 1`] = `
368 | #!/usr/bin/env pwsh
369 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
370 |
371 | $exe=""
372 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
373 | # Fix case when both the Windows and Linux builds of Node
374 | # are installed in the same directory
375 | $exe=".exe"
376 | }
377 | # Support pipeline input
378 | if ($MyInvocation.ExpectingInput) {
379 | $input | & "$basedir/from.exe" $args
380 | } else {
381 | & "$basedir/from.exe" $args
382 | }
383 | exit $LASTEXITCODE
384 |
385 | `
386 |
387 | exports[`test/basic.js TAP if exists (it does exist) > shell 1`] = `
388 | #!/bin/sh
389 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
390 |
391 | case \`uname\` in
392 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
393 | esac
394 |
395 | exec "$basedir/from.exe" "$@"
396 |
397 | `
398 |
399 | exports[`test/basic.js TAP just proceed if reading fails > cmd 1`] = `
400 | @ECHO off\\r
401 | GOTO start\\r
402 | :find_dp0\\r
403 | SET dp0=%~dp0\\r
404 | EXIT /b\\r
405 | :start\\r
406 | SETLOCAL\\r
407 | CALL :find_dp0\\r
408 | "%dp0%\\" %*\\r
409 |
410 | `
411 |
412 | exports[`test/basic.js TAP just proceed if reading fails > ps1 1`] = `
413 | #!/usr/bin/env pwsh
414 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
415 |
416 | $exe=""
417 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
418 | # Fix case when both the Windows and Linux builds of Node
419 | # are installed in the same directory
420 | $exe=".exe"
421 | }
422 | # Support pipeline input
423 | if ($MyInvocation.ExpectingInput) {
424 | $input | & "$basedir/" $args
425 | } else {
426 | & "$basedir/" $args
427 | }
428 | exit $LASTEXITCODE
429 |
430 | `
431 |
432 | exports[`test/basic.js TAP just proceed if reading fails > shell 1`] = `
433 | #!/bin/sh
434 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
435 |
436 | case \`uname\` in
437 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
438 | esac
439 |
440 | exec "$basedir/" "$@"
441 |
442 | `
443 |
444 | exports[`test/basic.js TAP no shebang > cmd 1`] = `
445 | @ECHO off\\r
446 | GOTO start\\r
447 | :find_dp0\\r
448 | SET dp0=%~dp0\\r
449 | EXIT /b\\r
450 | :start\\r
451 | SETLOCAL\\r
452 | CALL :find_dp0\\r
453 | "%dp0%\\from.exe" %*\\r
454 |
455 | `
456 |
457 | exports[`test/basic.js TAP no shebang > ps1 1`] = `
458 | #!/usr/bin/env pwsh
459 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
460 |
461 | $exe=""
462 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
463 | # Fix case when both the Windows and Linux builds of Node
464 | # are installed in the same directory
465 | $exe=".exe"
466 | }
467 | # Support pipeline input
468 | if ($MyInvocation.ExpectingInput) {
469 | $input | & "$basedir/from.exe" $args
470 | } else {
471 | & "$basedir/from.exe" $args
472 | }
473 | exit $LASTEXITCODE
474 |
475 | `
476 |
477 | exports[`test/basic.js TAP no shebang > shell 1`] = `
478 | #!/bin/sh
479 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
480 |
481 | case \`uname\` in
482 | *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;;
483 | esac
484 |
485 | exec "$basedir/from.exe" "$@"
486 |
487 | `
488 |
--------------------------------------------------------------------------------
/tap-snapshots/test/basic.js.test.cjs:
--------------------------------------------------------------------------------
1 | /* IMPORTANT
2 | * This snapshot file is auto-generated, but designed for humans.
3 | * It should be checked into source control and tracked carefully.
4 | * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
5 | * Make sure to inspect the output below. Do not ignore changes!
6 | */
7 | 'use strict'
8 | exports[`test/basic.js TAP env shebang > cmd 1`] = `
9 | @ECHO off\\r
10 | GOTO start\\r
11 | :find_dp0\\r
12 | SET dp0=%~dp0\\r
13 | EXIT /b\\r
14 | :start\\r
15 | SETLOCAL\\r
16 | CALL :find_dp0\\r
17 | \\r
18 | IF EXIST "%dp0%\\node.exe" (\\r
19 | SET "_prog=%dp0%\\node.exe"\\r
20 | ) ELSE (\\r
21 | SET "_prog=node"\\r
22 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
23 | )\\r
24 | \\r
25 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\from.env" %*\\r
26 |
27 | `
28 |
29 | exports[`test/basic.js TAP env shebang > ps1 1`] = `
30 | #!/usr/bin/env pwsh
31 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
32 |
33 | $exe=""
34 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
35 | # Fix case when both the Windows and Linux builds of Node
36 | # are installed in the same directory
37 | $exe=".exe"
38 | }
39 | $ret=0
40 | if (Test-Path "$basedir/node$exe") {
41 | # Support pipeline input
42 | if ($MyInvocation.ExpectingInput) {
43 | $input | & "$basedir/node$exe" "$basedir/from.env" $args
44 | } else {
45 | & "$basedir/node$exe" "$basedir/from.env" $args
46 | }
47 | $ret=$LASTEXITCODE
48 | } else {
49 | # Support pipeline input
50 | if ($MyInvocation.ExpectingInput) {
51 | $input | & "node$exe" "$basedir/from.env" $args
52 | } else {
53 | & "node$exe" "$basedir/from.env" $args
54 | }
55 | $ret=$LASTEXITCODE
56 | }
57 | exit $ret
58 |
59 | `
60 |
61 | exports[`test/basic.js TAP env shebang > shell 1`] = `
62 | #!/bin/sh
63 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
64 |
65 | case \`uname\` in
66 | *CYGWIN*|*MINGW*|*MSYS*)
67 | if command -v cygpath > /dev/null 2>&1; then
68 | basedir=\`cygpath -w "$basedir"\`
69 | fi
70 | ;;
71 | esac
72 |
73 | if [ -x "$basedir/node" ]; then
74 | exec "$basedir/node" "$basedir/from.env" "$@"
75 | else
76 | exec node "$basedir/from.env" "$@"
77 | fi
78 |
79 | `
80 |
81 | exports[`test/basic.js TAP env shebang with args > cmd 1`] = `
82 | @ECHO off\\r
83 | GOTO start\\r
84 | :find_dp0\\r
85 | SET dp0=%~dp0\\r
86 | EXIT /b\\r
87 | :start\\r
88 | SETLOCAL\\r
89 | CALL :find_dp0\\r
90 | \\r
91 | IF EXIST "%dp0%\\node.exe" (\\r
92 | SET "_prog=%dp0%\\node.exe"\\r
93 | ) ELSE (\\r
94 | SET "_prog=node"\\r
95 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
96 | )\\r
97 | \\r
98 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" --expose_gc "%dp0%\\from.env.args" %*\\r
99 |
100 | `
101 |
102 | exports[`test/basic.js TAP env shebang with args > ps1 1`] = `
103 | #!/usr/bin/env pwsh
104 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
105 |
106 | $exe=""
107 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
108 | # Fix case when both the Windows and Linux builds of Node
109 | # are installed in the same directory
110 | $exe=".exe"
111 | }
112 | $ret=0
113 | if (Test-Path "$basedir/node$exe") {
114 | # Support pipeline input
115 | if ($MyInvocation.ExpectingInput) {
116 | $input | & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args
117 | } else {
118 | & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args
119 | }
120 | $ret=$LASTEXITCODE
121 | } else {
122 | # Support pipeline input
123 | if ($MyInvocation.ExpectingInput) {
124 | $input | & "node$exe" --expose_gc "$basedir/from.env.args" $args
125 | } else {
126 | & "node$exe" --expose_gc "$basedir/from.env.args" $args
127 | }
128 | $ret=$LASTEXITCODE
129 | }
130 | exit $ret
131 |
132 | `
133 |
134 | exports[`test/basic.js TAP env shebang with args > shell 1`] = `
135 | #!/bin/sh
136 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
137 |
138 | case \`uname\` in
139 | *CYGWIN*|*MINGW*|*MSYS*)
140 | if command -v cygpath > /dev/null 2>&1; then
141 | basedir=\`cygpath -w "$basedir"\`
142 | fi
143 | ;;
144 | esac
145 |
146 | if [ -x "$basedir/node" ]; then
147 | exec "$basedir/node" --expose_gc "$basedir/from.env.args" "$@"
148 | else
149 | exec node --expose_gc "$basedir/from.env.args" "$@"
150 | fi
151 |
152 | `
153 |
154 | exports[`test/basic.js TAP env shebang with variables > cmd 1`] = `
155 | @ECHO off\\r
156 | GOTO start\\r
157 | :find_dp0\\r
158 | SET dp0=%~dp0\\r
159 | EXIT /b\\r
160 | :start\\r
161 | SETLOCAL\\r
162 | CALL :find_dp0\\r
163 | @SET NODE_PATH=./lib:%NODE_PATH%\\r
164 | \\r
165 | IF EXIST "%dp0%\\node.exe" (\\r
166 | SET "_prog=%dp0%\\node.exe"\\r
167 | ) ELSE (\\r
168 | SET "_prog=node"\\r
169 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
170 | )\\r
171 | \\r
172 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\from.env.variables" %*\\r
173 |
174 | `
175 |
176 | exports[`test/basic.js TAP env shebang with variables > ps1 1`] = `
177 | #!/usr/bin/env pwsh
178 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
179 |
180 | $exe=""
181 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
182 | # Fix case when both the Windows and Linux builds of Node
183 | # are installed in the same directory
184 | $exe=".exe"
185 | }
186 | $ret=0
187 | if (Test-Path "$basedir/node$exe") {
188 | # Support pipeline input
189 | if ($MyInvocation.ExpectingInput) {
190 | $input | & "$basedir/node$exe" "$basedir/from.env.variables" $args
191 | } else {
192 | & "$basedir/node$exe" "$basedir/from.env.variables" $args
193 | }
194 | $ret=$LASTEXITCODE
195 | } else {
196 | # Support pipeline input
197 | if ($MyInvocation.ExpectingInput) {
198 | $input | & "node$exe" "$basedir/from.env.variables" $args
199 | } else {
200 | & "node$exe" "$basedir/from.env.variables" $args
201 | }
202 | $ret=$LASTEXITCODE
203 | }
204 | exit $ret
205 |
206 | `
207 |
208 | exports[`test/basic.js TAP env shebang with variables > shell 1`] = `
209 | #!/bin/sh
210 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
211 |
212 | case \`uname\` in
213 | *CYGWIN*|*MINGW*|*MSYS*)
214 | if command -v cygpath > /dev/null 2>&1; then
215 | basedir=\`cygpath -w "$basedir"\`
216 | fi
217 | ;;
218 | esac
219 |
220 | if [ -x "$basedir/node" ]; then
221 | exec NODE_PATH=./lib:$NODE_PATH "$basedir/node" "$basedir/from.env.variables" "$@"
222 | else
223 | exec NODE_PATH=./lib:$NODE_PATH node "$basedir/from.env.variables" "$@"
224 | fi
225 |
226 | `
227 |
228 | exports[`test/basic.js TAP explicit shebang > cmd 1`] = `
229 | @ECHO off\\r
230 | GOTO start\\r
231 | :find_dp0\\r
232 | SET dp0=%~dp0\\r
233 | EXIT /b\\r
234 | :start\\r
235 | SETLOCAL\\r
236 | CALL :find_dp0\\r
237 | \\r
238 | IF EXIST "%dp0%\\/usr/bin/sh.exe" (\\r
239 | SET "_prog=%dp0%\\/usr/bin/sh.exe"\\r
240 | ) ELSE (\\r
241 | SET "_prog=/usr/bin/sh"\\r
242 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
243 | )\\r
244 | \\r
245 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\\from.sh" %*\\r
246 |
247 | `
248 |
249 | exports[`test/basic.js TAP explicit shebang > ps1 1`] = `
250 | #!/usr/bin/env pwsh
251 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
252 |
253 | $exe=""
254 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
255 | # Fix case when both the Windows and Linux builds of Node
256 | # are installed in the same directory
257 | $exe=".exe"
258 | }
259 | $ret=0
260 | if (Test-Path "$basedir//usr/bin/sh$exe") {
261 | # Support pipeline input
262 | if ($MyInvocation.ExpectingInput) {
263 | $input | & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args
264 | } else {
265 | & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args
266 | }
267 | $ret=$LASTEXITCODE
268 | } else {
269 | # Support pipeline input
270 | if ($MyInvocation.ExpectingInput) {
271 | $input | & "/usr/bin/sh$exe" "$basedir/from.sh" $args
272 | } else {
273 | & "/usr/bin/sh$exe" "$basedir/from.sh" $args
274 | }
275 | $ret=$LASTEXITCODE
276 | }
277 | exit $ret
278 |
279 | `
280 |
281 | exports[`test/basic.js TAP explicit shebang > shell 1`] = `
282 | #!/bin/sh
283 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
284 |
285 | case \`uname\` in
286 | *CYGWIN*|*MINGW*|*MSYS*)
287 | if command -v cygpath > /dev/null 2>&1; then
288 | basedir=\`cygpath -w "$basedir"\`
289 | fi
290 | ;;
291 | esac
292 |
293 | if [ -x "$basedir//usr/bin/sh" ]; then
294 | exec "$basedir//usr/bin/sh" "$basedir/from.sh" "$@"
295 | else
296 | exec /usr/bin/sh "$basedir/from.sh" "$@"
297 | fi
298 |
299 | `
300 |
301 | exports[`test/basic.js TAP explicit shebang with args > cmd 1`] = `
302 | @ECHO off\\r
303 | GOTO start\\r
304 | :find_dp0\\r
305 | SET dp0=%~dp0\\r
306 | EXIT /b\\r
307 | :start\\r
308 | SETLOCAL\\r
309 | CALL :find_dp0\\r
310 | \\r
311 | IF EXIST "%dp0%\\/usr/bin/sh.exe" (\\r
312 | SET "_prog=%dp0%\\/usr/bin/sh.exe"\\r
313 | ) ELSE (\\r
314 | SET "_prog=/usr/bin/sh"\\r
315 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
316 | )\\r
317 | \\r
318 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" -x "%dp0%\\from.sh.args" %*\\r
319 |
320 | `
321 |
322 | exports[`test/basic.js TAP explicit shebang with args > ps1 1`] = `
323 | #!/usr/bin/env pwsh
324 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
325 |
326 | $exe=""
327 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
328 | # Fix case when both the Windows and Linux builds of Node
329 | # are installed in the same directory
330 | $exe=".exe"
331 | }
332 | $ret=0
333 | if (Test-Path "$basedir//usr/bin/sh$exe") {
334 | # Support pipeline input
335 | if ($MyInvocation.ExpectingInput) {
336 | $input | & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
337 | } else {
338 | & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
339 | }
340 | $ret=$LASTEXITCODE
341 | } else {
342 | # Support pipeline input
343 | if ($MyInvocation.ExpectingInput) {
344 | $input | & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
345 | } else {
346 | & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args
347 | }
348 | $ret=$LASTEXITCODE
349 | }
350 | exit $ret
351 |
352 | `
353 |
354 | exports[`test/basic.js TAP explicit shebang with args > shell 1`] = `
355 | #!/bin/sh
356 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
357 |
358 | case \`uname\` in
359 | *CYGWIN*|*MINGW*|*MSYS*)
360 | if command -v cygpath > /dev/null 2>&1; then
361 | basedir=\`cygpath -w "$basedir"\`
362 | fi
363 | ;;
364 | esac
365 |
366 | if [ -x "$basedir//usr/bin/sh" ]; then
367 | exec "$basedir//usr/bin/sh" -x "$basedir/from.sh.args" "$@"
368 | else
369 | exec /usr/bin/sh -x "$basedir/from.sh.args" "$@"
370 | fi
371 |
372 | `
373 |
374 | exports[`test/basic.js TAP if exists (it does exist) > cmd 1`] = `
375 | @ECHO off\\r
376 | GOTO start\\r
377 | :find_dp0\\r
378 | SET dp0=%~dp0\\r
379 | EXIT /b\\r
380 | :start\\r
381 | SETLOCAL\\r
382 | CALL :find_dp0\\r
383 | "%dp0%\\from.exe" %*\\r
384 |
385 | `
386 |
387 | exports[`test/basic.js TAP if exists (it does exist) > ps1 1`] = `
388 | #!/usr/bin/env pwsh
389 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
390 |
391 | $exe=""
392 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
393 | # Fix case when both the Windows and Linux builds of Node
394 | # are installed in the same directory
395 | $exe=".exe"
396 | }
397 | # Support pipeline input
398 | if ($MyInvocation.ExpectingInput) {
399 | $input | & "$basedir/from.exe" $args
400 | } else {
401 | & "$basedir/from.exe" $args
402 | }
403 | exit $LASTEXITCODE
404 |
405 | `
406 |
407 | exports[`test/basic.js TAP if exists (it does exist) > shell 1`] = `
408 | #!/bin/sh
409 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
410 |
411 | case \`uname\` in
412 | *CYGWIN*|*MINGW*|*MSYS*)
413 | if command -v cygpath > /dev/null 2>&1; then
414 | basedir=\`cygpath -w "$basedir"\`
415 | fi
416 | ;;
417 | esac
418 |
419 | exec "$basedir/from.exe" "$@"
420 |
421 | `
422 |
423 | exports[`test/basic.js TAP just proceed if reading fails > cmd 1`] = `
424 | @ECHO off\\r
425 | GOTO start\\r
426 | :find_dp0\\r
427 | SET dp0=%~dp0\\r
428 | EXIT /b\\r
429 | :start\\r
430 | SETLOCAL\\r
431 | CALL :find_dp0\\r
432 | "%dp0%\\" %*\\r
433 |
434 | `
435 |
436 | exports[`test/basic.js TAP just proceed if reading fails > ps1 1`] = `
437 | #!/usr/bin/env pwsh
438 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
439 |
440 | $exe=""
441 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
442 | # Fix case when both the Windows and Linux builds of Node
443 | # are installed in the same directory
444 | $exe=".exe"
445 | }
446 | # Support pipeline input
447 | if ($MyInvocation.ExpectingInput) {
448 | $input | & "$basedir/" $args
449 | } else {
450 | & "$basedir/" $args
451 | }
452 | exit $LASTEXITCODE
453 |
454 | `
455 |
456 | exports[`test/basic.js TAP just proceed if reading fails > shell 1`] = `
457 | #!/bin/sh
458 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
459 |
460 | case \`uname\` in
461 | *CYGWIN*|*MINGW*|*MSYS*)
462 | if command -v cygpath > /dev/null 2>&1; then
463 | basedir=\`cygpath -w "$basedir"\`
464 | fi
465 | ;;
466 | esac
467 |
468 | exec "$basedir/" "$@"
469 |
470 | `
471 |
472 | exports[`test/basic.js TAP multiple variables > cmd 1`] = `
473 | @ECHO off\\r
474 | GOTO start\\r
475 | :find_dp0\\r
476 | SET dp0=%~dp0\\r
477 | EXIT /b\\r
478 | :start\\r
479 | SETLOCAL\\r
480 | CALL :find_dp0\\r
481 | @SET key=value\\r
482 | @SET key2=value2\\r
483 | \\r
484 | IF EXIST "%dp0%\\node.exe" (\\r
485 | SET "_prog=%dp0%\\node.exe"\\r
486 | ) ELSE (\\r
487 | SET "_prog=node"\\r
488 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
489 | )\\r
490 | \\r
491 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" --flag-one --flag-two "%dp0%\\from.env.multiple.variables" %*\\r
492 |
493 | `
494 |
495 | exports[`test/basic.js TAP multiple variables > ps1 1`] = `
496 | #!/usr/bin/env pwsh
497 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
498 |
499 | $exe=""
500 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
501 | # Fix case when both the Windows and Linux builds of Node
502 | # are installed in the same directory
503 | $exe=".exe"
504 | }
505 | $ret=0
506 | if (Test-Path "$basedir/node$exe") {
507 | # Support pipeline input
508 | if ($MyInvocation.ExpectingInput) {
509 | $input | & "$basedir/node$exe" --flag-one --flag-two "$basedir/from.env.multiple.variables" $args
510 | } else {
511 | & "$basedir/node$exe" --flag-one --flag-two "$basedir/from.env.multiple.variables" $args
512 | }
513 | $ret=$LASTEXITCODE
514 | } else {
515 | # Support pipeline input
516 | if ($MyInvocation.ExpectingInput) {
517 | $input | & "node$exe" --flag-one --flag-two "$basedir/from.env.multiple.variables" $args
518 | } else {
519 | & "node$exe" --flag-one --flag-two "$basedir/from.env.multiple.variables" $args
520 | }
521 | $ret=$LASTEXITCODE
522 | }
523 | exit $ret
524 |
525 | `
526 |
527 | exports[`test/basic.js TAP multiple variables > shell 1`] = `
528 | #!/bin/sh
529 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
530 |
531 | case \`uname\` in
532 | *CYGWIN*|*MINGW*|*MSYS*)
533 | if command -v cygpath > /dev/null 2>&1; then
534 | basedir=\`cygpath -w "$basedir"\`
535 | fi
536 | ;;
537 | esac
538 |
539 | if [ -x "$basedir/node" ]; then
540 | exec key=value key2=value2 "$basedir/node" --flag-one --flag-two "$basedir/from.env.multiple.variables" "$@"
541 | else
542 | exec key=value key2=value2 node --flag-one --flag-two "$basedir/from.env.multiple.variables" "$@"
543 | fi
544 |
545 | `
546 |
547 | exports[`test/basic.js TAP no shebang > cmd 1`] = `
548 | @ECHO off\\r
549 | GOTO start\\r
550 | :find_dp0\\r
551 | SET dp0=%~dp0\\r
552 | EXIT /b\\r
553 | :start\\r
554 | SETLOCAL\\r
555 | CALL :find_dp0\\r
556 | "%dp0%\\from.exe" %*\\r
557 |
558 | `
559 |
560 | exports[`test/basic.js TAP no shebang > ps1 1`] = `
561 | #!/usr/bin/env pwsh
562 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
563 |
564 | $exe=""
565 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
566 | # Fix case when both the Windows and Linux builds of Node
567 | # are installed in the same directory
568 | $exe=".exe"
569 | }
570 | # Support pipeline input
571 | if ($MyInvocation.ExpectingInput) {
572 | $input | & "$basedir/from.exe" $args
573 | } else {
574 | & "$basedir/from.exe" $args
575 | }
576 | exit $LASTEXITCODE
577 |
578 | `
579 |
580 | exports[`test/basic.js TAP no shebang > shell 1`] = `
581 | #!/bin/sh
582 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
583 |
584 | case \`uname\` in
585 | *CYGWIN*|*MINGW*|*MSYS*)
586 | if command -v cygpath > /dev/null 2>&1; then
587 | basedir=\`cygpath -w "$basedir"\`
588 | fi
589 | ;;
590 | esac
591 |
592 | exec "$basedir/from.exe" "$@"
593 |
594 | `
595 |
596 | exports[`test/basic.js TAP shebang with env -S > cmd 1`] = `
597 | @ECHO off\\r
598 | GOTO start\\r
599 | :find_dp0\\r
600 | SET dp0=%~dp0\\r
601 | EXIT /b\\r
602 | :start\\r
603 | SETLOCAL\\r
604 | CALL :find_dp0\\r
605 | \\r
606 | IF EXIST "%dp0%\\node.exe" (\\r
607 | SET "_prog=%dp0%\\node.exe"\\r
608 | ) ELSE (\\r
609 | SET "_prog=node"\\r
610 | SET PATHEXT=%PATHEXT:;.JS;=;%\\r
611 | )\\r
612 | \\r
613 | endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" --expose_gc "%dp0%\\from.env.S" %*\\r
614 |
615 | `
616 |
617 | exports[`test/basic.js TAP shebang with env -S > cmd 2`] = `
618 | #!/usr/bin/env pwsh
619 | $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
620 |
621 | $exe=""
622 | if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
623 | # Fix case when both the Windows and Linux builds of Node
624 | # are installed in the same directory
625 | $exe=".exe"
626 | }
627 | $ret=0
628 | if (Test-Path "$basedir/node$exe") {
629 | # Support pipeline input
630 | if ($MyInvocation.ExpectingInput) {
631 | $input | & "$basedir/node$exe" --expose_gc "$basedir/from.env.S" $args
632 | } else {
633 | & "$basedir/node$exe" --expose_gc "$basedir/from.env.S" $args
634 | }
635 | $ret=$LASTEXITCODE
636 | } else {
637 | # Support pipeline input
638 | if ($MyInvocation.ExpectingInput) {
639 | $input | & "node$exe" --expose_gc "$basedir/from.env.S" $args
640 | } else {
641 | & "node$exe" --expose_gc "$basedir/from.env.S" $args
642 | }
643 | $ret=$LASTEXITCODE
644 | }
645 | exit $ret
646 |
647 | `
648 |
649 | exports[`test/basic.js TAP shebang with env -S > shell 1`] = `
650 | #!/bin/sh
651 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
652 |
653 | case \`uname\` in
654 | *CYGWIN*|*MINGW*|*MSYS*)
655 | if command -v cygpath > /dev/null 2>&1; then
656 | basedir=\`cygpath -w "$basedir"\`
657 | fi
658 | ;;
659 | esac
660 |
661 | if [ -x "$basedir/node" ]; then
662 | exec "$basedir/node" --expose_gc "$basedir/from.env.S" "$@"
663 | else
664 | exec node --expose_gc "$basedir/from.env.S" "$@"
665 | fi
666 |
667 | `
668 |
--------------------------------------------------------------------------------
/test/00-setup.js:
--------------------------------------------------------------------------------
1 | const {
2 | mkdirSync,
3 | writeFileSync,
4 | } = require('fs')
5 |
6 | const fixtures = require('path').join(__dirname, '/fixtures')
7 |
8 | const froms = {
9 | 'from.exe': 'exe',
10 | 'from.env': '#!/usr/bin/env node\nconsole.log(/hi/)\n',
11 | 'from.env.args': '#!/usr/bin/env node --expose_gc\ngc()\n',
12 | 'from.env.variables': '#!/usr/bin/env NODE_PATH=./lib:$NODE_PATH node',
13 | 'from.sh': '#!/usr/bin/sh\necho hi\n',
14 | 'from.sh.args': '#!/usr/bin/sh -x\necho hi\n',
15 | 'from.env.multiple.variables': '#!/usr/bin/env key=value key2=value2 node --flag-one --flag-two',
16 | 'from.env.S': '#!/usr/bin/env -S node --expose_gc\ngc()\n',
17 | 'from.env.nospace': '#!/usr/bin/envnode\nconsole.log(/hi/)\n',
18 | }
19 |
20 | mkdirSync(fixtures, { recursive: true })
21 | for (const [f, content] of Object.entries(froms)) {
22 | writeFileSync(`${fixtures}/${f}`, content)
23 | }
24 |
--------------------------------------------------------------------------------
/test/basic.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | var test = require('tap').test
4 | var fs = require('fs')
5 | var path = require('path')
6 | var fixtures = path.resolve(__dirname, 'fixtures')
7 |
8 | const matchSnapshot = (t, found, name) =>
9 | t.matchSnapshot(found.replace(/\r/g, '\\r'), name)
10 |
11 | var cmdShim = require('..')
12 |
13 | test('no shebang', async t => {
14 | var from = path.resolve(fixtures, 'from.exe')
15 | var to = path.resolve(fixtures, 'exe.shim')
16 | await cmdShim(from, to)
17 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
18 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
19 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
20 | })
21 |
22 | test('if exists (it does exist)', async t => {
23 | var from = path.resolve(fixtures, 'from.exe')
24 | var to = path.resolve(fixtures, 'exe.shim')
25 | await cmdShim.ifExists(from, to)
26 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
27 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
28 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
29 | })
30 |
31 | test('if exists (it does not exist)', async t => {
32 | var from = path.resolve(fixtures, 'argle bargle we like to sparkle')
33 | var to = path.resolve(fixtures, 'argle-bargle-shim')
34 | await cmdShim.ifExists(from, to)
35 | t.throws(() => fs.statSync(to))
36 | t.throws(() => fs.statSync(to + '.cmd'))
37 | t.throws(() => fs.statSync(to + '.ps1'))
38 | })
39 |
40 | test('fails if from doesnt exist', async t => {
41 | var from = path.resolve(fixtures, 'argle bargle we like to sparkle')
42 | var to = path.resolve(fixtures, 'argle-bargle-shim')
43 | await t.rejects(cmdShim(from, to), { code: 'ENOENT' })
44 | })
45 |
46 | test('fails if mkdir fails', async t => {
47 | var from = path.resolve(fixtures, 'from.env')
48 | var to = path.resolve(fixtures, 'from.env/a/b/c')
49 | await t.rejects(cmdShim(from, to), { code: /^(ENOTDIR|EEXIST|ENOENT)$/ })
50 | })
51 |
52 | test('fails if to is a dir', async t => {
53 | var from = path.resolve(fixtures, 'from.env')
54 | var to = path.resolve(fixtures)
55 | t.teardown(() => {
56 | fs.rmSync(to + '.cmd', { recursive: true, force: true })
57 | })
58 | await t.rejects(cmdShim(from, to), { code: 'EISDIR' })
59 | })
60 |
61 | test('just proceed if reading fails', async t => {
62 | var from = fixtures
63 | var to = path.resolve(fixtures, 'env.shim')
64 | await cmdShim(from, to)
65 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
66 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
67 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
68 | })
69 |
70 | test('env shebang', async t => {
71 | var from = path.resolve(fixtures, 'from.env')
72 | var to = path.resolve(fixtures, 'env.shim')
73 | await cmdShim(from, to)
74 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
75 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
76 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
77 | })
78 |
79 | test('env shebang with args', async t => {
80 | var from = path.resolve(fixtures, 'from.env.args')
81 | var to = path.resolve(fixtures, 'env.args.shim')
82 | await cmdShim(from, to)
83 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
84 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
85 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
86 | })
87 |
88 | test('env shebang with variables', async t => {
89 | var from = path.resolve(fixtures, 'from.env.variables')
90 | var to = path.resolve(fixtures, 'env.variables.shim')
91 | await cmdShim(from, to)
92 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
93 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
94 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
95 | })
96 |
97 | test('explicit shebang', async t => {
98 | var from = path.resolve(fixtures, 'from.sh')
99 | var to = path.resolve(fixtures, 'sh.shim')
100 | await cmdShim(from, to)
101 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
102 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
103 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
104 | })
105 |
106 | test('explicit shebang with args', async t => {
107 | var from = path.resolve(fixtures, 'from.sh.args')
108 | var to = path.resolve(fixtures, 'sh.args.shim')
109 | await cmdShim(from, to)
110 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
111 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
112 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
113 | })
114 |
115 | test('multiple variables', async t => {
116 | var from = path.resolve(fixtures, 'from.env.multiple.variables')
117 | var to = path.resolve(fixtures, 'sh.multiple.shim')
118 | await cmdShim(from, to)
119 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
120 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
121 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
122 | })
123 |
124 | test('shebang with env -S', async t => {
125 | var from = path.resolve(fixtures, 'from.env.S')
126 | var to = path.resolve(fixtures, 'sh.env.S.shim')
127 | await cmdShim(from, to)
128 | matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
129 | matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
130 | matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'cmd')
131 | })
132 |
--------------------------------------------------------------------------------
/test/to-batch-syntax-tests.js:
--------------------------------------------------------------------------------
1 | var test = require('tap').test
2 | var toBatchSyntax = require('../lib/to-batch-syntax')
3 |
4 | test('replace $ expressions with % pair', function (t) {
5 | var assertReplacement = function (string, expected) {
6 | t.equal(toBatchSyntax.replaceDollarWithPercentPair(string), expected)
7 | }
8 | assertReplacement('$A', '%A%')
9 | assertReplacement('$A:$B', '%A%:%B%')
10 | assertReplacement('$A bla', '%A% bla')
11 | assertReplacement('${A}bla', '%A%bla')
12 | assertReplacement('$A $bla bla', '%A% %bla% bla')
13 | assertReplacement('${A}bla ${bla}bla', '%A%bla %bla%bla')
14 | assertReplacement('./lib:$NODE_PATH', './lib:%NODE_PATH%')
15 | t.end()
16 | })
17 |
18 | test('convert variable declaration to set command', function (t) {
19 | t.equal(toBatchSyntax.convertToSetCommand('A', '.lib:$A '), '@SET A=.lib:%A%\r\n')
20 | t.equal(toBatchSyntax.convertToSetCommand('', ''), '')
21 | t.equal(toBatchSyntax.convertToSetCommand(' ', ''), '')
22 | t.equal(toBatchSyntax.convertToSetCommand(' ', ' '), '')
23 | t.equal(toBatchSyntax.convertToSetCommand(' ou', ' ou '), '@SET ou=ou\r\n')
24 | t.end()
25 | })
26 |
--------------------------------------------------------------------------------
/test/zz-cleanup.js:
--------------------------------------------------------------------------------
1 | const { join } = require('path')
2 | const { rmSync } = require('fs')
3 |
4 | rmSync(join(__dirname, 'fixtures'), { recursive: true, force: true })
5 | rmSync(join(__dirname, 'fixtures.ps1'))
6 |
--------------------------------------------------------------------------------