fix(ui): make chapter bridge manual-only and add release gate
Remove auto chapter-bridge prompt on book/chapter open so users trigger it from the cockpit. Fix AiPanel duplicate import that broke dev builds, and add release smoke tests plus test:release/test:ci scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { readFileSync, readdirSync, statSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
const ROOT = join(import.meta.dirname, '../..')
|
||||
|
||||
function collectSourceFiles(dir: string, acc: string[] = []): string[] {
|
||||
for (const name of readdirSync(dir)) {
|
||||
const full = join(dir, name)
|
||||
const st = statSync(full)
|
||||
if (st.isDirectory()) {
|
||||
if (name === 'node_modules' || name === 'out') continue
|
||||
collectSourceFiles(full, acc)
|
||||
} else if (/\.(ts|tsx)$/.test(name)) {
|
||||
acc.push(full)
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
function extractNamedImports(content: string): { from: string; names: string[] }[] {
|
||||
const results: { from: string; names: string[] }[] = []
|
||||
const re = /import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g
|
||||
let m: RegExpExecArray | null
|
||||
while ((m = re.exec(content)) !== null) {
|
||||
const names = m[1]
|
||||
.split(',')
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean)
|
||||
.map((part) => part.split(/\s+as\s+/)[0]!.trim())
|
||||
results.push({ from: m[2]!, names })
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
describe('release gate: import hygiene', () => {
|
||||
it('UT-RELEASE-01: no duplicate named imports from the same module', () => {
|
||||
const files = collectSourceFiles(join(ROOT, 'src'))
|
||||
const offenders: string[] = []
|
||||
|
||||
for (const file of files) {
|
||||
const blocks = extractNamedImports(readFileSync(file, 'utf8'))
|
||||
const seen = new Map<string, Set<string>>()
|
||||
for (const { from, names } of blocks) {
|
||||
if (!seen.has(from)) seen.set(from, new Set())
|
||||
const bucket = seen.get(from)!
|
||||
for (const name of names) {
|
||||
if (bucket.has(name)) {
|
||||
offenders.push(`${file}: duplicate import { ${name} } from '${from}'`)
|
||||
}
|
||||
bucket.add(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(offenders, offenders.join('\n')).toEqual([])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user