From 467c8b99bdff8b4d158145db6207189128b01562 Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Fri, 13 Nov 2026 07:31:46 +0400 Subject: [PATCH] build-ts: keep a package homepage that points outside the repository (0.86.9) (#34) * build-ts: keep a package homepage that points outside the repository orderPackageJson derived homepage from repository.url on every build, so a package could not link its npm page to its API reference: the build put the repository readme back and the clean-tree check failed. A homepage inside the repository, or none, is still derived as before. * Release dev, dev-test and dev-ts together as 0.86.9 --- packages/dev-test/package.json | 2 +- packages/dev-test/src/packageInfo.ts | 2 +- packages/dev-ts/package.json | 2 +- packages/dev-ts/src/packageInfo.ts | 2 +- packages/dev/package.json | 6 +-- packages/dev/scripts/pezkuwi-dev-build-ts.mjs | 4 +- packages/dev/scripts/util.mjs | 18 ++++++++ packages/dev/src/packageHomepage.spec.ts | 42 +++++++++++++++++++ packages/dev/src/packageInfo.ts | 2 +- yarn.lock | 8 ++-- 10 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 packages/dev/src/packageHomepage.spec.ts diff --git a/packages/dev-test/package.json b/packages/dev-test/package.json index 339306b..1446507 100644 --- a/packages/dev-test/package.json +++ b/packages/dev-test/package.json @@ -15,7 +15,7 @@ }, "sideEffects": false, "type": "module", - "version": "0.86.8", + "version": "0.86.9", "main": "./index.js", "exports": { "./globals.d.ts": "./src/globals.d.ts" diff --git a/packages/dev-test/src/packageInfo.ts b/packages/dev-test/src/packageInfo.ts index 5ba5961..481c463 100644 --- a/packages/dev-test/src/packageInfo.ts +++ b/packages/dev-test/src/packageInfo.ts @@ -3,4 +3,4 @@ // Do not edit, auto-generated by @pezkuwi/dev -export const packageInfo = { name: '@pezkuwi/dev-test', path: 'auto', type: 'auto', version: '0.86.8' }; +export const packageInfo = { name: '@pezkuwi/dev-test', path: 'auto', type: 'auto', version: '0.86.9' }; diff --git a/packages/dev-ts/package.json b/packages/dev-ts/package.json index 5679996..a411390 100644 --- a/packages/dev-ts/package.json +++ b/packages/dev-ts/package.json @@ -15,7 +15,7 @@ }, "sideEffects": false, "type": "module", - "version": "0.86.8", + "version": "0.86.9", "main": "./index.js", "exports": { "./globals.d.ts": "./src/globals.d.ts" diff --git a/packages/dev-ts/src/packageInfo.ts b/packages/dev-ts/src/packageInfo.ts index 1f9f3ca..47f6b87 100644 --- a/packages/dev-ts/src/packageInfo.ts +++ b/packages/dev-ts/src/packageInfo.ts @@ -3,4 +3,4 @@ // Do not edit, auto-generated by @pezkuwi/dev -export const packageInfo = { name: '@pezkuwi/dev-ts', path: 'auto', type: 'auto', version: '0.86.8' }; +export const packageInfo = { name: '@pezkuwi/dev-ts', path: 'auto', type: 'auto', version: '0.86.9' }; diff --git a/packages/dev/package.json b/packages/dev/package.json index 26e898f..12d3986 100644 --- a/packages/dev/package.json +++ b/packages/dev/package.json @@ -15,7 +15,7 @@ }, "sideEffects": false, "type": "module", - "version": "0.86.8", + "version": "0.86.9", "bin": { "pezkuwi-ci-ghact-build": "./scripts/pezkuwi-ci-ghact-build.mjs", "pezkuwi-ci-ghact-docs": "./scripts/pezkuwi-ci-ghact-docs.mjs", @@ -52,8 +52,8 @@ "dependencies": { "@eslint/compat": "^2.1.1", "@eslint/js": "^10.0.1", - "@pezkuwi/dev-test": "^0.86.8", - "@pezkuwi/dev-ts": "^0.86.8", + "@pezkuwi/dev-test": "^0.86.9", + "@pezkuwi/dev-ts": "^0.86.9", "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-commonjs": "^29.0.3", "@rollup/plugin-dynamic-import-vars": "^2.1.5", diff --git a/packages/dev/scripts/pezkuwi-dev-build-ts.mjs b/packages/dev/scripts/pezkuwi-dev-build-ts.mjs index 428494a..fc896a1 100755 --- a/packages/dev/scripts/pezkuwi-dev-build-ts.mjs +++ b/packages/dev/scripts/pezkuwi-dev-build-ts.mjs @@ -9,7 +9,7 @@ import path from 'node:path'; import process from 'node:process'; import ts from 'typescript'; -import { copyDirSync, copyFileSync, DENO_EXT_PRE, DENO_LND_PRE, DENO_POL_PRE, engineVersionCmp, execPm, exitFatal, exitFatalEngine, logBin, mkdirpSync, PATHS_BUILD, readdirSync, rimrafSync } from './util.mjs'; +import { copyDirSync, copyFileSync, DENO_EXT_PRE, DENO_LND_PRE, DENO_POL_PRE, engineVersionCmp, execPm, exitFatal, exitFatalEngine, logBin, mkdirpSync, packageHomepage, PATHS_BUILD, readdirSync, rimrafSync } from './util.mjs'; /** @typedef {'babel' | 'esbuild' | 'swc' | 'tsc'} CompileType */ /** @typedef {{ bin?: Record; browser?: string; bugs?: string; deno?: string; denoDependencies?: Record; dependencies?: Record; devDependencies?: Record; electron?: string; engines?: { node?: string }; exports?: Record; license?: string; homepage?: string; main?: string; module?: string; name?: string; optionalDependencies?: Record; peerDependencies?: Record; repository?: { directory?: string; type: 'git'; url: string; }; 'react-native'?: string; resolutions?: Record; sideEffects?: boolean | string[]; scripts?: Record; type?: 'module' | 'commonjs'; types?: string; version?: string; }} PkgJson */ @@ -973,7 +973,7 @@ function repoBaseFromUrl (url) { */ function orderPackageJson (repoBase, dir, json) { json.bugs = `${repoBase}/issues`; - json.homepage = `${repoBase}${dir ? `/tree/master/packages/${dir}` : ''}#readme`; + json.homepage = packageHomepage(repoBase, dir, json.homepage); json.license = !json.license || json.license === 'Apache-2' ? 'Apache-2.0' : json.license; diff --git a/packages/dev/scripts/util.mjs b/packages/dev/scripts/util.mjs index 8bafc2b..ae21a08 100644 --- a/packages/dev/scripts/util.mjs +++ b/packages/dev/scripts/util.mjs @@ -146,6 +146,24 @@ export function engineVersionSplit (ver) { return [parseInt(parts[0] || '0', 10), parseInt(parts[1] || '0', 10), parseInt(parts[2] || '0', 10)]; } +/** + * The homepage written into a package.json. One the author pointed outside the + * repository (an API reference, a product site) is kept; anything else, and an + * absent one, is derived from the repository. + * + * @param {string} repoBase e.g. https://git.example.org/owner/repo + * @param {string | null} dir package directory under packages/, null for the root + * @param {string} [current] the homepage the package.json carries now + * @returns {string} + */ +export function packageHomepage (repoBase, dir, current) { + const inRepo = !current || current === repoBase || current.startsWith(`${repoBase}/`) || current.startsWith(`${repoBase}#`); + + return inRepo + ? `${repoBase}${dir ? `/tree/master/packages/${dir}` : ''}#readme` + : current; +} + /** * Process execution * diff --git a/packages/dev/src/packageHomepage.spec.ts b/packages/dev/src/packageHomepage.spec.ts new file mode 100644 index 0000000..fc52fdc --- /dev/null +++ b/packages/dev/src/packageHomepage.spec.ts @@ -0,0 +1,42 @@ +// Copyright 2017-2026 @pezkuwi/dev authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +/// + +import { execFileSync } from 'node:child_process'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const UTIL = pathToFileURL(path.join(process.cwd(), 'packages/dev/scripts/util.mjs')).href; +const REPO = 'https://git.example.org/owner/repo'; + +// util.mjs is plain ESM outside the TypeScript build, so it is called the way +// pezkuwi-dev-build-ts calls it: from node. +function homepage (dir: string | null, current?: string): string { + const code = `import { packageHomepage } from ${JSON.stringify(UTIL)}; +process.stdout.write(packageHomepage(${JSON.stringify(REPO)}, ${JSON.stringify(dir)}, ${current === undefined ? 'undefined' : JSON.stringify(current)}));`; + + return execFileSync(process.execPath, ['--input-type=module', '-e', code], { encoding: 'utf8' }); +} + +describe('packageHomepage', (): void => { + it('derives the homepage when there is none', (): void => { + expect(homepage('api')).toBe(`${REPO}/tree/master/packages/api#readme`); + expect(homepage(null)).toBe(`${REPO}#readme`); + }); + + it('rewrites a homepage inside the repository', (): void => { + expect(homepage('api', `${REPO}/tree/main/packages/api#readme`)).toBe(`${REPO}/tree/master/packages/api#readme`); + expect(homepage(null, `${REPO}#readme`)).toBe(`${REPO}#readme`); + expect(homepage(null, REPO)).toBe(`${REPO}#readme`); + }); + + it('keeps a homepage outside the repository', (): void => { + expect(homepage('api', 'https://developers.example.org/modules/api.html')).toBe('https://developers.example.org/modules/api.html'); + expect(homepage(null, 'https://developers.example.org/')).toBe('https://developers.example.org/'); + }); + + it('does not take a sibling repository for this one', (): void => { + expect(homepage('api', `${REPO}-docs`)).toBe(`${REPO}-docs`); + }); +}); diff --git a/packages/dev/src/packageInfo.ts b/packages/dev/src/packageInfo.ts index 51a0879..5d4ee46 100644 --- a/packages/dev/src/packageInfo.ts +++ b/packages/dev/src/packageInfo.ts @@ -3,4 +3,4 @@ // Do not edit, auto-generated by @pezkuwi/dev -export const packageInfo = { name: '@pezkuwi/dev', path: 'auto', type: 'auto', version: '0.86.8' }; +export const packageInfo = { name: '@pezkuwi/dev', path: 'auto', type: 'auto', version: '0.86.9' }; diff --git a/yarn.lock b/yarn.lock index a0f51fb..e3ebb09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1196,7 +1196,7 @@ __metadata: languageName: node linkType: hard -"@pezkuwi/dev-test@npm:^0.86.8, @pezkuwi/dev-test@workspace:packages/dev-test": +"@pezkuwi/dev-test@npm:^0.86.9, @pezkuwi/dev-test@workspace:packages/dev-test": version: 0.0.0-use.local resolution: "@pezkuwi/dev-test@workspace:packages/dev-test" dependencies: @@ -1212,7 +1212,7 @@ __metadata: languageName: unknown linkType: soft -"@pezkuwi/dev-ts@npm:^0.86.8, @pezkuwi/dev-ts@workspace:packages/dev-ts": +"@pezkuwi/dev-ts@npm:^0.86.9, @pezkuwi/dev-ts@workspace:packages/dev-ts": version: 0.0.0-use.local resolution: "@pezkuwi/dev-ts@workspace:packages/dev-ts" dependencies: @@ -1228,8 +1228,8 @@ __metadata: dependencies: "@eslint/compat": "npm:^2.1.1" "@eslint/js": "npm:^10.0.1" - "@pezkuwi/dev-test": "npm:^0.86.8" - "@pezkuwi/dev-ts": "npm:^0.86.8" + "@pezkuwi/dev-test": "npm:^0.86.9" + "@pezkuwi/dev-ts": "npm:^0.86.9" "@rollup/plugin-alias": "npm:^5.1.1" "@rollup/plugin-commonjs": "npm:^29.0.3" "@rollup/plugin-dynamic-import-vars": "npm:^2.1.5"