The seed was being SIGKILL'd on Railway (512MB limit) because fast-xml-parser
built a ~300MB object tree from the 120MB OFAC SDN XML download, causing both
the raw XML string and the full parsed object to coexist in heap simultaneously.
Switch to sax (already a transitive dep) with a streaming pipeline: response.body
is piped chunk-by-chunk via a TextDecoder into the SAX parser. The full XML
string is never held in memory. Reference maps (areaCodes, featureTypes,
legalBasis, locations, parties) are populated as SAX events arrive, and entries
are emitted one at a time on </SanctionsEntry>.
All DOM-traversal helpers (listify, textValue, buildEpoch, buildReferenceMaps,
buildLocationMap, extractPartyName, resolveEntityType, extractPartyCountries,
buildPartyMap, extractPrograms, extractEffectiveAt, extractNote,
buildEntriesForDocument) are removed. Output-stage pure functions (uniqueSorted,
compactNote, sortEntries, buildCountryPressure, buildProgramPressure) are kept.
Tests updated to match: removed test blocks for deleted DOM helpers, kept
coverage for the remaining pure functions (2173/2173 pass).
Tests cover all pure helper functions in scripts/seed-sanctions-pressure.mjs:
listify, textValue, buildEpoch, uniqueSorted, compactNote,
extractDocumentedName, normalizeDateOfIssue, buildReferenceMaps,
buildLocationMap, resolveEntityType, extractPartyName, extractPrograms,
extractEffectiveAt, extractNote, sortEntries, buildCountryPressure,
buildProgramPressure, and an end-to-end buildEntriesForDocument fixture.
Uses node:vm to load pure functions in an isolated context, bypassing
the loadEnvFile + runSeed side effects that fire on module import.