Files
msd-core/tests/package-name-single-source.test.cjs
Tom Boucher 79002a00cb chore(#518): rename npm package + bin to @opengsd/gsd-core (#519)
* chore: rename npm package + bin to @opengsd/gsd-core (functional)

- package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core,
  bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs
- package-lock.json: regenerated (npm install --package-lock-only)
- tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**,
  get-shit-done/bin/**, get-shit-done/workflows/**:
  applied the 4-rule replacement (scoped npm ref, GitHub repo path,
  bin/clone invocations) per #505 single-source refactor

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: sweep live references to @opengsd/gsd-core

Update all live documentation (README.md + translations, docs/**,
CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md,
docs/CANARY.md) to reflect the renamed package and repository.

Rules applied:
- @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name)
- open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo)
- GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org)
- bare bin/clone refs → gsd-core

CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**,
and .changeset/** are preserved byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: add negative lookbehind to slash-command regex in bug-2954 test

The extractSlashReferences regex matched /gsd-core inside npm package
URLs (@opengsd/gsd-core), producing a false /gsd:core command reference.
Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a
letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(#518): add changeset for package rename

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(#518): update package-identity expectations to the renamed coordinates

The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo
open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL
package.json, so their expected literals must follow the rename. The drift-lint
unit test is left as-is — its SEAM is a self-consistent fixture and its
stale-literal detection cases would shift if altered; the live-repo scan in it
already passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:25:02 -04:00

116 lines
3.9 KiB
JavaScript

'use strict';
/**
* Lint guard: the package name must be single-sourced from package-identity.cjs.
*
* Scans runtime files (bin/install.js, get-shit-done/bin/**, scripts/*.cjs)
* and FAILS if the literal `@opengsd/gsd-core` appears in a
* non-comment, non-identity-module line. This enforces that a future rename
* is a one-file change in package.json (#516).
*
* Comment lines are detected by checking if the trimmed line starts with
* `//`, `*`, or `/*` (best-effort; covers all common JS comment forms).
*
* Tests:
* 1. No code-literal occurrences of the package name in runtime files
* (outside the identity module itself).
* 2. PACKAGE_NAME exported from the identity module equals package.json name.
*/
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { execSync } = require('node:child_process');
const ROOT = path.join(__dirname, '..');
const LITERAL = '@opengsd/gsd-core';
const IDENTITY_MODULE = path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'package-identity.cjs');
// Files to scan: bin/install.js + everything under get-shit-done/bin/ + touched scripts
function getRuntimeFiles() {
const files = [];
// bin/install.js
const installJs = path.join(ROOT, 'bin', 'install.js');
if (fs.existsSync(installJs)) files.push(installJs);
// get-shit-done/bin/**/*.cjs and *.js (recursive)
function collectDir(dir) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
collectDir(fullPath);
} else if (entry.isFile() && /\.(cjs|js)$/.test(entry.name)) {
files.push(fullPath);
}
}
}
collectDir(path.join(ROOT, 'get-shit-done', 'bin'));
// scripts/*.cjs
for (const entry of fs.readdirSync(path.join(ROOT, 'scripts'), { withFileTypes: true })) {
if (entry.isFile() && entry.name.endsWith('.cjs')) {
files.push(path.join(ROOT, 'scripts', entry.name));
}
}
// scripts/changeset/*.cjs
const changesetDir = path.join(ROOT, 'scripts', 'changeset');
if (fs.existsSync(changesetDir)) {
for (const entry of fs.readdirSync(changesetDir, { withFileTypes: true })) {
if (entry.isFile() && entry.name.endsWith('.cjs')) {
files.push(path.join(changesetDir, entry.name));
}
}
}
return files;
}
function isCommentLine(trimmed) {
return (
trimmed.startsWith('//') ||
trimmed.startsWith('*') ||
trimmed.startsWith('/*')
);
}
test('no hardcoded @opengsd/gsd-core literals in runtime non-comment code lines (#516)', () => {
const files = getRuntimeFiles();
const violations = [];
for (const file of files) {
// Skip the identity module itself — it legitimately contains the literal
if (path.resolve(file) === path.resolve(IDENTITY_MODULE)) continue;
const content = fs.readFileSync(file, 'utf-8');
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (!line.includes(LITERAL)) continue;
const trimmed = line.trimStart();
if (isCommentLine(trimmed)) continue;
violations.push(`${path.relative(ROOT, file)}:${i + 1}: ${line.trim()}`);
}
}
assert.deepEqual(
violations,
[],
`Found ${violations.length} hardcoded @opengsd/gsd-core literal(s) in non-comment code lines:\n` +
violations.map(v => ` ${v}`).join('\n') +
'\n\nReplace each with the PACKAGE_NAME imported from get-shit-done/bin/lib/package-identity.cjs'
);
});
test('PACKAGE_NAME from identity module matches package.json name (#516)', () => {
const { PACKAGE_NAME } = require('../get-shit-done/bin/lib/package-identity.cjs');
const pkgJson = require('../package.json');
assert.equal(
PACKAGE_NAME,
pkgJson.name,
`Identity module PACKAGE_NAME (${PACKAGE_NAME}) must equal package.json name (${pkgJson.name})`
);
});