Files
dsh-web/scripts/aggregate.test.mjs
T
zhu1090093659 d05bf03350 fix(web-ui-all): expand external plugin bundles and restore better-session 0.0.11
@morlay/better-session ships as a profile bundle (dsh.bundle.patch), so
writing its package name into an insert row made the loader import a
module that does not exist and dsh web failed to boot. The aggregate
generator now expands bundle rows: parsePatchBlocks accepts name-less
harness patch rows (preserving extra lines such as disabled flags),
insert ids stay namespaced, later bundle patches override earlier same-id
rows, and external children are resolved from the aggregate package.
link-profile.mjs links bundle child packages so profile-root imports
resolve. Upstream republished 0.0.11, pinned with release-age excludes.

Verified by aggregate --check (19 rows / 17 deps), test:scripts,
dump-config row shape, and profile-side resolvability; runtime effect
requires the user restarting dsh web.
2026-08-27 20:07:11 +08:00

120 lines
5.3 KiB
JavaScript

/**
* Aggregate patch invariants: every INSERT row id is web-ui-* namespaced and
* unique within one aggregate, and no aggregate id collides with any
* standalone package's own row id (the coexistence guarantee). The generated
* files are the contract — scripts/aggregate.mjs --check enforces drift
* separately.
*/
import { existsSync, readdirSync, readFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import assert from 'node:assert/strict'
import { test } from 'node:test'
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
const ROOT = join(SCRIPT_DIR, '..')
/** Parse the INSERT row ids of one cordis.patch.yml (rows are indented under
* an `- insert:` block; top-level `- id:` entries are excluded). */
function idsOf(relPath) {
const lines = readFileSync(join(ROOT, relPath), 'utf8').split(/\r?\n/)
return lines
.filter((line) => /^ {4}- id: /.test(line))
.map((line) => line.trim().replace(/^- id: /, ''))
}
const AGGREGATES = ['packages/dsh-web-all/cordis.patch.yml']
test('aggregate rows are web-ui-* namespaced and unique', () => {
for (const rel of AGGREGATES) {
const ids = idsOf(rel)
assert.ok(ids.length > 0, `${rel} should carry rows`)
assert.equal(new Set(ids).size, ids.length, `${rel} ids must be unique`)
for (const id of ids) {
assert.match(id, /^web-ui-[a-z0-9-]+$/, `${rel} id must be namespaced: ${id}`)
}
}
})
test('aggregate ids never collide with standalone package ids', () => {
const aggregateIds = new Set(AGGREGATES.flatMap(idsOf))
const standalonePatches = []
for (const base of ['packages', 'packages/skins']) {
for (const entry of readdirSync(join(ROOT, base), { withFileTypes: true })) {
if (!entry.isDirectory()) continue
const patch = join(base, entry.name, 'cordis.patch.yml')
const abs = join(ROOT, patch)
try {
readFileSync(abs)
} catch {
continue
}
const normPatch = patch.replaceAll('\\', '/')
if (normPatch === 'packages/dsh-web-all/cordis.patch.yml') continue
standalonePatches.push(patch)
}
}
assert.ok(standalonePatches.length > 10, 'expected to scan the standalone packages')
for (const patch of standalonePatches) {
for (const id of idsOf(patch)) {
assert.ok(!aggregateIds.has(id), `aggregate id "${id}" collides with standalone row in ${patch}`)
}
}
})
test('no aggregate deps entry resolves to a private workspace package', () => {
const aggregates = []
for (const base of ['packages', 'packages/skins']) {
for (const entry of readdirSync(join(ROOT, base), { withFileTypes: true })) {
if (!entry.isDirectory()) continue
const yml = join(base, entry.name, 'aggregate.yml')
if (existsSync(join(ROOT, yml))) aggregates.push(yml)
}
}
assert.ok(aggregates.length >= 1, 'expected at least one aggregate manifest')
for (const yml of aggregates) {
let section = null
for (const raw of readFileSync(join(ROOT, yml), 'utf8').split(/\r?\n/)) {
const line = raw.trim()
if (!line || line.startsWith('#')) continue
const sectionMatch = line.match(/^[A-Za-z0-9_-]+:\s*$/)
if (sectionMatch) {
section = line.slice(0, -1)
continue
}
if (section !== 'deps' || !line.startsWith('- ')) continue
const entry = line.slice(2).trim().replace(/\s+#.*$/, '')
const pkgPath = join(ROOT, dirname(yml), entry, 'package.json')
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
assert.notEqual(pkg.private, true, 'aggregate deps entry is private: ' + yml + ' -> ' + entry)
}
}
})
test('web-ui-all mounts dsh-better-sidebar as an external row', () => {
const patch = readFileSync(join(ROOT, 'packages/dsh-web-all/cordis.patch.yml'), 'utf8')
const lines = patch.split(/\r?\n/)
const idx = lines.findIndex((line) => /^ {4}- id: web-ui-better-sidebar$/.test(line))
assert.ok(idx >= 0, 'web-ui-better-sidebar row is missing from the aggregate patch')
// The paired name line resolves the row from the profile root (npm package).
assert.match(lines[idx + 1] ?? '', /^ {6}name: 'dsh-better-sidebar'$/)
})
test('web-ui-all mounts @mlgbnb/dsh-archive-manager as an external row', () => {
const patch = readFileSync(join(ROOT, 'packages/dsh-web-all/cordis.patch.yml'), 'utf8')
const lines = patch.split(/\r?\n/)
const idx = lines.findIndex((line) => /^ {4}- id: web-ui-archive-manager$/.test(line))
assert.ok(idx >= 0, 'web-ui-archive-manager row is missing from the aggregate patch')
// The paired name line resolves the scoped npm package from the profile root.
assert.match(lines[idx + 1] ?? '', /^ {6}name: '@mlgbnb\/dsh-archive-manager'$/)
})
test('web-ui-all expands @morlay/better-session into importable bundle rows', () => {
const patch = readFileSync(join(ROOT, 'packages/dsh-web-all/cordis.patch.yml'), 'utf8')
assert.doesNotMatch(patch, /web-ui-better-session/, 'bundle-only package must not be emitted as an importable row')
for (const id of ['web-ui-session-branch', 'web-ui-session-rdb', 'web-ui-conversation-message-actions']) {
assert.match(patch, new RegExp(`^ {4}- id: ${id}$`, 'm'), `external bundle row ${id} is missing`)
}
assert.match(patch, /^- id: session-persistence-jsonl\s+disabled: true/m, 'external bundle must keep its harness-row patch')
})