mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-28 18:05:29 -04:00
* feat: add native set-script command with ss alias * refactor(pkg-manifest): host set-script and wire it into the CLI - Move set-script into @pnpm/pkg-manifest.commands (drops the orphan @pnpm/pkg.commands package; pkg/* is not in the workspace). - Use readProjectManifest from @pnpm/cli.utils so package.json5 and package.yaml are updated in place instead of growing a stray package.json. - Remove set-script from notImplemented and register the command in pnpm/src/cmd/index.ts. - Cover the ss alias and the multi-word command path in tests. * refactor(set-script): share the pkg-set primitive Replace direct manifest.scripts mutation with setObjectValueByPropertyPath - the same primitive pkg-set uses. Reuses the prototype-pollution rejection for free and keeps the two commands on the same write path. Avoids the pkg-set string-CLI's first-equals key/value split, so script names containing '=' work too. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
|
|
import { beforeEach, describe, expect, test } from '@jest/globals'
|
|
import { setScript } from '@pnpm/pkg-manifest.commands'
|
|
import { tempDir } from '@pnpm/prepare'
|
|
|
|
describe('set-script command', () => {
|
|
let tmpDir: string
|
|
|
|
beforeEach(() => {
|
|
tmpDir = tempDir()
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, 'package.json'),
|
|
JSON.stringify({ name: 'test-package', version: '1.0.0' }, null, 2)
|
|
)
|
|
})
|
|
|
|
test('exposes the ss alias', () => {
|
|
expect(setScript.commandNames).toEqual(['set-script', 'ss'])
|
|
})
|
|
|
|
test('adds a script when none exist', async () => {
|
|
await setScript.handler({ dir: tmpDir }, ['build', 'tsc -b'])
|
|
|
|
const written = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf8'))
|
|
expect(written.scripts).toEqual({ build: 'tsc -b' })
|
|
})
|
|
|
|
test('overwrites an existing script', async () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, 'package.json'),
|
|
JSON.stringify({ name: 'test-package', scripts: { build: 'old' } }, null, 2)
|
|
)
|
|
|
|
await setScript.handler({ dir: tmpDir }, ['build', 'tsc -b'])
|
|
|
|
const written = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf8'))
|
|
expect(written.scripts.build).toBe('tsc -b')
|
|
})
|
|
|
|
test('joins remaining params into the command', async () => {
|
|
await setScript.handler({ dir: tmpDir }, ['lint', 'eslint', '--fix', 'src'])
|
|
|
|
const written = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf8'))
|
|
expect(written.scripts.lint).toBe('eslint --fix src')
|
|
})
|
|
|
|
test('accepts script names that contain dots, hyphens, and quotes', async () => {
|
|
await setScript.handler({ dir: tmpDir }, ['my-build', 'tsc -b'])
|
|
await setScript.handler({ dir: tmpDir }, ['pre.publish', 'echo'])
|
|
await setScript.handler({ dir: tmpDir }, ['weird"name', 'echo weird'])
|
|
|
|
const written = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf8'))
|
|
expect(written.scripts).toEqual({
|
|
'my-build': 'tsc -b',
|
|
'pre.publish': 'echo',
|
|
'weird"name': 'echo weird',
|
|
})
|
|
})
|
|
|
|
test('accepts script names containing an equals sign', async () => {
|
|
await setScript.handler({ dir: tmpDir }, ['with=eq', 'echo with=eq'])
|
|
|
|
const written = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf8'))
|
|
expect(written.scripts['with=eq']).toBe('echo with=eq')
|
|
})
|
|
|
|
test('throws when arguments are missing', async () => {
|
|
await expect(setScript.handler({ dir: tmpDir }, ['build']))
|
|
.rejects.toThrow('Missing script name or command')
|
|
})
|
|
|
|
test('rejects unsafe script names', async () => {
|
|
await expect(setScript.handler({ dir: tmpDir }, ['__proto__', 'echo']))
|
|
.rejects.toThrow()
|
|
})
|
|
})
|