From 6f074865f57f4007eaa5cca84d83adf50517b307 Mon Sep 17 00:00:00 2001 From: Kohei Otsuka Date: Fri, 6 Nov 2026 21:20:20 +0900 Subject: [PATCH] =?UTF-8?q?fix(scripts):=20sync-version.js=20=E3=81=8C=20p?= =?UTF-8?q?rerelease=20=E3=81=AE=E7=89=88=E3=82=92=E6=89=B1=E3=81=88?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 版の正規表現を \d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)? にし、1.3.0-rc.1 のような prerelease を 1 つの版として置き換える。これまでは [\d.]+ が 1.2.0 の部分だけを 拾い、-rc.1 が後ろに残っていた - 置き換えるのは、もともと版を書いている箇所だけにする。版の無い `npm install @maplat/<名前>` などに版を足していた挙動をやめる - 一時ディレクトリに写した README で、prerelease 版と通常の版への同期を確かめる テストを足す Co-Authored-By: Claude Opus 5.5 --- scripts/sync-version.js | 26 ++++++------- tests/sync-version.test.ts | 80 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 tests/sync-version.test.ts diff --git a/scripts/sync-version.js b/scripts/sync-version.js index f8ad0f0..9b35120 100644 --- a/scripts/sync-version.js +++ b/scripts/sync-version.js @@ -1,7 +1,7 @@ #!/bin/env node -// MaplatTransform/scripts/sync-version.js — M1-T1 修正版 -// 設計書: docs/superpowers/specs/2026-09-10-M1-T1-design.md §3.1 -// 変更: npm install/npm: パターンのオプショナル化、CDN URL パターン追加、Current release パターン追加 +// package.json の version を README.md・README.ja.mdへ写す。 +// 置き換えるのは、もともと版を書いている箇所だけ。版の無い `npm install @maplat/<名前>` などには版を足さない。 +// 版は prerelease(例 1.3.0-rc.1)を含めて 1 つの版として扱う。 import fs from 'node:fs'; import path from 'node:path'; @@ -23,22 +23,22 @@ const filesToUpdate = [ path: path.join(rootDir, 'README.md'), type: 'markdown', patterns: [ - { regex: /npm install @maplat\/transform(?:@[\d.]+)?/g, replacement: `npm install @maplat/transform@${version}` }, - { regex: /npm:@maplat\/transform(?:@[\d.]+)?/g, replacement: `npm:@maplat/transform@${version}` }, - { regex: /cdn\.jsdelivr\.net\/npm\/@maplat\/transform@[\d.]+/g, replacement: `cdn.jsdelivr.net/npm/@maplat/transform@${version}` }, - { regex: /Current release: `[\d.]+`/g, replacement: `Current release: \`${version}\`` }, - { regex: /現在のリリース: `[\d.]+`/g, replacement: `現在のリリース: \`${version}\`` } + { regex: /npm install @maplat\/transform@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g, replacement: `npm install @maplat/transform@${version}` }, + { regex: /npm:@maplat\/transform@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g, replacement: `npm:@maplat/transform@${version}` }, + { regex: /cdn\.jsdelivr\.net\/npm\/@maplat\/transform@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g, replacement: `cdn.jsdelivr.net/npm/@maplat/transform@${version}` }, + { regex: /Current release: `\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?`/g, replacement: `Current release: \`${version}\`` }, + { regex: /現在のリリース: `\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?`/g, replacement: `現在のリリース: \`${version}\`` } ] }, { path: path.join(rootDir, 'README.ja.md'), type: 'markdown', patterns: [ - { regex: /npm install @maplat\/transform(?:@[\d.]+)?/g, replacement: `npm install @maplat/transform@${version}` }, - { regex: /npm:@maplat\/transform(?:@[\d.]+)?/g, replacement: `npm:@maplat/transform@${version}` }, - { regex: /cdn\.jsdelivr\.net\/npm\/@maplat\/transform@[\d.]+/g, replacement: `cdn.jsdelivr.net/npm/@maplat/transform@${version}` }, - { regex: /Current release: `[\d.]+`/g, replacement: `Current release: \`${version}\`` }, - { regex: /現在のリリース: `[\d.]+`/g, replacement: `現在のリリース: \`${version}\`` } + { regex: /npm install @maplat\/transform@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g, replacement: `npm install @maplat/transform@${version}` }, + { regex: /npm:@maplat\/transform@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g, replacement: `npm:@maplat/transform@${version}` }, + { regex: /cdn\.jsdelivr\.net\/npm\/@maplat\/transform@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g, replacement: `cdn.jsdelivr.net/npm/@maplat/transform@${version}` }, + { regex: /Current release: `\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?`/g, replacement: `Current release: \`${version}\`` }, + { regex: /現在のリリース: `\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?`/g, replacement: `現在のリリース: \`${version}\`` } ] } ]; diff --git a/tests/sync-version.test.ts b/tests/sync-version.test.ts new file mode 100644 index 0000000..77ee26c --- /dev/null +++ b/tests/sync-version.test.ts @@ -0,0 +1,80 @@ +import { execFileSync } from 'node:child_process'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; + +// scripts/sync-version.js を一時ディレクトリへ写し、写しの README だけを書き換えさせる +const SCRIPT = resolve(__dirname, '../scripts/sync-version.js'); +const PKG = '@maplat/transform'; + +// もともと版を書いている形(どれも 1.2.0-rc.1 を持たせる) +const VERSIONED_PREFIXES = [ + 'npm install @maplat/transform', + 'npm:@maplat/transform' +]; + +// 版の無い形(版を足してはいけない) +const UNVERSIONED_LINES = [`npm install ${PKG}`, `pnpm add ${PKG}`]; + +const readme = (releaseLabel: string): string => + [ + `> **${releaseLabel}: \`1.2.0-rc.1\`**`, + '', + ...UNVERSIONED_LINES, + ...VERSIONED_PREFIXES.map((p) => `${p}@1.2.0-rc.1`), + `npm install ${PKG}@1.1.0`, + ``, + '' + ].join('\n'); + +const dirs: string[] = []; + +const run = (version: string): { en: string; ja: string } => { + const dir = mkdtempSync(join(tmpdir(), 'sync-version-')); + dirs.push(dir); + mkdirSync(join(dir, 'scripts')); + copyFileSync(SCRIPT, join(dir, 'scripts', 'sync-version.js')); + writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: PKG, version, type: 'module' })); + writeFileSync(join(dir, 'README.md'), readme('Current release')); + writeFileSync(join(dir, 'README.ja.md'), readme('現在のリリース')); + execFileSync(process.execPath, [join(dir, 'scripts', 'sync-version.js')], { stdio: 'pipe' }); + return { + en: readFileSync(join(dir, 'README.md'), 'utf8'), + ja: readFileSync(join(dir, 'README.ja.md'), 'utf8') + }; +}; + +afterEach(() => { + for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true }); +}); + +describe('sync-version.js with prerelease versions', () => { + it('replaces every versioned reference with a prerelease version and leaves unversioned lines alone', () => { + const { en, ja } = run('1.3.0-rc.2'); + for (const text of [en, ja]) { + const lines = text.split('\n'); + for (const p of VERSIONED_PREFIXES) expect(lines).toContain(`${p}@1.3.0-rc.2`); + for (const line of UNVERSIONED_LINES) expect(lines).toContain(line); + expect(text).toContain(`cdn.jsdelivr.net/npm/${PKG}@1.3.0-rc.2/dist/index.umd.js`); + expect(text).not.toContain('-rc.1'); + expect(text).not.toContain('1.2.0'); + expect(text).not.toContain('1.1.0'); + } + expect(en).toContain('Current release: `1.3.0-rc.2`'); + expect(ja).toContain('現在のリリース: `1.3.0-rc.2`'); + }); + + it('drops the prerelease suffix when moving to a stable version', () => { + const { en, ja } = run('1.3.0'); + for (const text of [en, ja]) { + const lines = text.split('\n'); + expect(text).not.toContain('-rc.'); + for (const p of VERSIONED_PREFIXES) expect(lines).toContain(`${p}@1.3.0`); + for (const line of UNVERSIONED_LINES) expect(lines).toContain(line); + expect(text).toContain(`cdn.jsdelivr.net/npm/${PKG}@1.3.0/dist/index.umd.js`); + } + expect(en).toContain('Current release: `1.3.0`'); + expect(ja).toContain('現在のリリース: `1.3.0`'); + }); +});