mirror of
https://github.com/zhu1090093659/dsh-web.git
synced 2026-09-29 17:08:39 +08:00
@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.
120 lines
5.3 KiB
JavaScript
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')
|
|
})
|