1
0

_v6.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import path from 'node:path'
  2. import os from 'node:os'
  3. import { fileURLToPath } from 'node:url'
  4. import { mkdtemp, rm, cp } from 'node:fs/promises'
  5. import { DatabaseSync } from 'node:sqlite'
  6. const __dirname = path.dirname(fileURLToPath(import.meta.url))
  7. export const inlineFixture = path.join(__dirname, '../fixtures/v6-inline')
  8. export const sqliteFixture = path.join(__dirname, '../fixtures/v6-sqlite')
  9. /** 拷 fixture 到临时目录(可写)。 */
  10. export async function tempV6(fixture) {
  11. const tmp = await mkdtemp(path.join(os.tmpdir(), 'wnw-v6-'))
  12. await cp(fixture, tmp, { recursive: true })
  13. return { v6Path: tmp, cleanup: () => rm(tmp, { recursive: true, force: true }) }
  14. }
  15. /**
  16. * 拷 v6-sqlite fixture 并现场建 index.db(DDL 摘自 v6 index_manager.py,
  17. * 见任务 research/v6-data-inventory.md Q3;故意不建 chase_debt 等表——测缺表容忍)。
  18. */
  19. export async function tempV6Sqlite() {
  20. const { v6Path, cleanup } = await tempV6(sqliteFixture)
  21. const db = new DatabaseSync(path.join(v6Path, '.webnovel', 'index.db'))
  22. db.exec(`CREATE TABLE entities (
  23. id TEXT PRIMARY KEY, type TEXT, canonical_name TEXT, tier TEXT DEFAULT '装饰',
  24. desc TEXT, current_json TEXT, first_appearance INTEGER, last_appearance INTEGER,
  25. is_protagonist INTEGER DEFAULT 0, is_archived INTEGER DEFAULT 0,
  26. created_at TEXT, updated_at TEXT)`)
  27. db.exec(`CREATE TABLE aliases (
  28. alias TEXT, entity_id TEXT, entity_type TEXT, created_at TEXT,
  29. PRIMARY KEY (alias, entity_id, entity_type))`)
  30. db.exec(`CREATE TABLE state_changes (
  31. id INTEGER PRIMARY KEY AUTOINCREMENT, entity_id TEXT, field TEXT,
  32. old_value TEXT, new_value TEXT, reason TEXT, chapter INTEGER, created_at TEXT)`)
  33. db.exec(`CREATE TABLE relationships (
  34. id INTEGER PRIMARY KEY AUTOINCREMENT, from_entity TEXT, to_entity TEXT,
  35. type TEXT, description TEXT, chapter INTEGER, created_at TEXT)`)
  36. db.exec(`CREATE TABLE chapters (
  37. chapter INTEGER PRIMARY KEY, title TEXT, location TEXT, word_count INTEGER,
  38. characters TEXT, summary TEXT, created_at TEXT)`)
  39. db.exec(`CREATE TABLE chapter_reading_power (
  40. chapter INTEGER PRIMARY KEY, hook_type TEXT, hook_strength TEXT DEFAULT 'medium',
  41. coolpoint_patterns TEXT, micropayoffs TEXT, hard_violations TEXT, soft_suggestions TEXT,
  42. is_transition INTEGER DEFAULT 0, override_count INTEGER DEFAULT 0,
  43. debt_balance REAL DEFAULT 0, created_at TEXT, updated_at TEXT)`)
  44. db.prepare(`INSERT INTO entities (id, type, canonical_name, tier, desc, current_json, first_appearance, last_appearance, is_protagonist)
  45. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
  46. .run('jiangyao', '角色', '江遥', '核心', '滨海市海事记者', '{"location":"滨海市","状态":"在世"}', 1, 2, 1)
  47. db.prepare(`INSERT INTO entities (id, type, canonical_name, tier, current_json, first_appearance, last_appearance)
  48. VALUES (?, ?, ?, ?, ?, ?, ?)`)
  49. .run('binhai', '地点', '滨海市', '支线', '{}', 1, 2)
  50. db.prepare('INSERT INTO aliases (alias, entity_id, entity_type) VALUES (?, ?, ?)').run('小江', 'jiangyao', '角色')
  51. db.prepare(`INSERT INTO state_changes (entity_id, field, old_value, new_value, reason, chapter)
  52. VALUES (?, ?, ?, ?, ?, ?)`).run('jiangyao', 'location', '报社', '滨海市', '回乡奔丧', 1)
  53. db.prepare(`INSERT INTO relationships (from_entity, to_entity, type, description, chapter)
  54. VALUES (?, ?, ?, ?, ?)`).run('jiangyao', 'binhai', '故乡', '江遥的故乡', 1)
  55. db.prepare('INSERT INTO chapters (chapter, title, summary) VALUES (?, ?, ?)')
  56. .run(1, '退潮', '江遥在退潮滩涂拾得停摆怀表,表盖刻字暗藏警告。')
  57. db.prepare('INSERT INTO chapter_reading_power (chapter, hook_type, hook_strength, coolpoint_patterns) VALUES (?, ?, ?, ?)')
  58. .run(1, '悬念钩', 'strong', '["异物入手"]')
  59. db.close()
  60. return { v6Path, cleanup }
  61. }