(dirRel: string)
| 1315 | export async function migrateLegacyDatabases(root: string): Promise<number> { |
| 1316 | let migrated = 0 |
| 1317 | const walk = async (dirRel: string): Promise<void> => { |
| 1318 | const dirAbs = dirRel ? path.join(root, dirRel) : root |
| 1319 | let entries: Dirent[] |
| 1320 | try { |
| 1321 | entries = await fs.readdir(dirAbs, { withFileTypes: true }) |
| 1322 | } catch { |
| 1323 | return |
| 1324 | } |
| 1325 | for (const entry of entries) { |
| 1326 | const name = entry.name |
| 1327 | if (name.startsWith('.')) continue |
| 1328 | const childRel = dirRel ? `${dirRel}/${name}` : name |
| 1329 | if (entry.isDirectory()) { |
| 1330 | if (isFormDirName(name)) continue // already a database folder |
| 1331 | await walk(childRel) |
| 1332 | continue |
| 1333 | } |
| 1334 | const lower = name.toLowerCase() |
| 1335 | if (!lower.endsWith('.csv') || lower.endsWith(`.csv${DATABASE_SIDECAR_SUFFIX}`)) continue |
| 1336 | // Only migrate a managed database (a `.csv` with a sibling sidecar); a |
| 1337 | // plain CSV without one is left as a file. |
| 1338 | const sidecarRel = `${childRel}${DATABASE_SIDECAR_SUFFIX}` |
| 1339 | try { |
| 1340 | await fs.access(resolveSafe(root, sidecarRel)) |
| 1341 | } catch { |
| 1342 | continue |
| 1343 | } |
| 1344 | try { |
| 1345 | if (await migrateOneLegacyDatabase(root, childRel, sidecarRel)) migrated++ |
| 1346 | } catch (err) { |
| 1347 | console.error(`database migration failed for ${childRel}`, err) |
| 1348 | } |
| 1349 | } |
| 1350 | } |
| 1351 | await walk('') |
| 1352 | if (migrated > 0) { |
| 1353 | console.log(`[zen] migrated ${migrated} database(s) to the .base folder layout`) |
no test coverage detected