// 稳健树状 dump:打印 JSON 路径结构,深度受控 import fs from 'node:fs'; import path from 'node:path'; const dir = path.resolve(process.argv[2] || '.cdp/out/api'); const which = process.argv[3] || '30d'; const files = fs.readdirSync(dir).filter(f => f.startsWith(which) && f.endsWith('.txt')).sort(); function deepFind(o, key, hits = [], p = '') { if (o === null || typeof o !== 'object') return hits; for (const k of Object.keys(o)) { const np = p ? p + '.' + k : k; if (k === key) hits.push({ path: np, value: o[k] }); deepFind(o[k], key, hits, np); } return hits; } function tree(o, p, d, out) { const ind = ' '.repeat(d); if (o === null) { out.push(ind + p + ' = null'); return; } if (Array.isArray(o)) { out.push(ind + p + ` [array len=${o.length}]`); if (o.length && typeof o[0] === 'object' && d < 4) tree(o[0], p + '[0]', d + 1, out); else if (o.length) out.push(ind + ' sample=' + JSON.stringify(o.slice(0, 6))); return; } if (typeof o === 'object') { out.push(ind + p + ' {' + Object.keys(o).length + '}'); if (d >= 5) return; for (const k of Object.keys(o)) tree(o[k], k, d + 1, out); return; } out.push(ind + p + ' = ' + JSON.stringify(o)); } for (const f of files) { const raw = fs.readFileSync(path.join(dir, f), 'utf8'); const i = raw.indexOf('\n\n'); const url = raw.slice(5, i).trim(); let body = raw.slice(i + 2).trim(); let json = null; try { json = JSON.parse(body); } catch { const m = body.match(/^[^(]*\((.*)\)[;\s]*$/s); if (m) { try { json = JSON.parse(m[1]); } catch {} } } console.log('\n' + '='.repeat(80)); console.log(f + ' ' + (url.match(/datacompass\.[A-Za-z0-9._]+/) || [''])[0]); if (!json) { console.log(' UNPARSED, head: ' + body.slice(0, 200)); continue; } console.log(' topLevelKeys = ' + JSON.stringify(Object.keys(json))); for (const h of deepFind(json, 'realDateRange')) console.log(' DATE ' + h.path + ' = ' + JSON.stringify(h.value)); const out = []; tree(json, '$', 0, out); console.log(out.slice(0, 90).join('\n')); if (out.length > 90) console.log(' ...(+' + (out.length - 90) + ' more lines)'); }