diff --git a/scripts/release/bump.mts b/scripts/release/bump.mts index e3579f4d7..960cac22e 100644 --- a/scripts/release/bump.mts +++ b/scripts/release/bump.mts @@ -159,8 +159,8 @@ function readPackageJson(): { parsed: PackageJsonShape; raw: string } { */ export function writeManifestVersion(raw: string, version: string): string { const replaced = raw.replace( - /^(\s*"version":\s*")[^"]*(")/m, - `$1${version}$2`, + /("version":\s*")[^"]+(")/, + (_m, pre: string, post: string) => `${pre}${version}${post}`, ) if (replaced === raw) { throw new Error( diff --git a/test/release-bump.test.mts b/test/release-bump.test.mts new file mode 100644 index 000000000..1dcd8bfad --- /dev/null +++ b/test/release-bump.test.mts @@ -0,0 +1,47 @@ +import { describe, expect, it } from 'vitest' + +import { writeManifestVersion } from '../scripts/release/bump.mts' + +describe('writeManifestVersion', () => { + it('rewrites the top-level version field, leaving everything else byte-for-byte', () => { + const raw = [ + '{', + ' "name": "socket",', + ' "version": "1.1.159",', + ' "description": "CLI for Socket.dev"', + '}', + '', + ].join('\n') + expect(writeManifestVersion(raw, '1.1.160')).toBe( + raw.replace('1.1.159', '1.1.160'), + ) + }) + + // The prior `^(\s*"version":\s*")[^"]*(")/m` anchor required the field to + // start a line. A minified (or otherwise reformatted) manifest still + // parses fine with JSON.parse, but broke that anchor and threw a false + // "no top-level version line" error — this is the exact failure this repo + // has hit intermittently on CI. The unanchored, non-multiline pattern + // matches the first "version": "…" occurrence regardless of surrounding + // whitespace. + it('rewrites the version field even when the manifest is minified', () => { + const raw = '{"name":"socket","version":"1.1.159","private":false}' + expect(writeManifestVersion(raw, '1.1.160')).toBe( + '{"name":"socket","version":"1.1.160","private":false}', + ) + }) + + it('throws when the manifest has no version field', () => { + const raw = '{\n "name": "socket"\n}\n' + expect(() => writeManifestVersion(raw, '1.1.160')).toThrow( + /could not rewrite the package\.json version field/, + ) + }) + + it('throws when the version field is already empty', () => { + const raw = '{\n "name": "socket",\n "version": ""\n}\n' + expect(() => writeManifestVersion(raw, '1.1.160')).toThrow( + /could not rewrite the package\.json version field/, + ) + }) +})