@financica/xbrl
v0.2.0
Published
TypeScript parser for XBRL 2.1 instance documents
Readme
xbrl
xbrl is a TypeScript library for reading and writing XBRL 2.1 instance documents as typed JavaScript objects. It focuses on practical reporting data: contexts, units, facts, schema references, and footnotes.
The library is designed for application code that needs a dependable parser and serialiser rather than a full validation pipeline. It resolves QNames, preserves reported values as strings, represents tuples recursively, and returns null instead of throwing when the input is empty, malformed, or not an XBRL instance document.
Parsing and writing are symmetric: parseXbrl(serializeXbrl(doc)) gives back doc.
Installation
npm install @financica/xbrlUsage
import { parseXbrl } from "@financica/xbrl";
import { readFileSync } from "node:fs";
const xml = readFileSync("filing.xbrl", "utf-8");
const instance = parseXbrl(xml);
if (instance) {
// Schema references
for (const ref of instance.schemaRefs) {
console.log(`Taxonomy: ${ref.href}`);
}
// Contexts
for (const [id, ctx] of Object.entries(instance.contexts)) {
console.log(`Context ${id}: ${ctx.entity.value} (${ctx.period.type})`);
}
// Units
for (const [id, unit] of Object.entries(instance.units)) {
const label =
unit.measures?.map((m) => m.localName).join("*") ??
`${unit.divide?.numerator.map((m) => m.localName).join("*")}/${unit.divide?.denominator.map((m) => m.localName).join("*")}`;
console.log(`Unit ${id}: ${label}`);
}
// Facts (recursive traversal)
function printFacts(facts: typeof instance.facts, indent = "") {
for (const fact of facts) {
if (fact.type === "item") {
console.log(
`${indent}${fact.name.localName} = ${fact.value} [${fact.contextRef}]`,
);
} else {
console.log(`${indent}${fact.name.localName} (tuple)`);
printFacts(fact.children, indent + " ");
}
}
}
printFacts(instance.facts);
}Writing
import { buildXbrlInstance, serializeXbrl } from "@financica/xbrl";
const doc = buildXbrlInstance({
schemaRefs: [{ href: "http://example.com/taxonomy.xsd" }],
contexts: [
{
id: "d1",
entity: { scheme: "http://example.com/scheme", value: "123" },
period: {
type: "duration",
startDate: "2025-01-01",
endDate: "2025-12-31",
},
},
],
units: [
{
id: "EUR",
measures: [
{ namespace: "http://www.xbrl.org/2003/iso4217", localName: "EUR" },
],
},
],
facts: [
{
type: "item",
name: {
namespace: "http://example.com/taxonomy",
localName: "Revenue",
prefix: "ex",
},
contextRef: "d1",
unitRef: "EUR",
decimals: 2,
value: "1000.00",
isNil: false,
},
],
});
const xml = serializeXbrl(doc);buildXbrlInstance normalises the document and rejects one that could not be
serialised: duplicate context or unit IDs, facts pointing at a context or unit
that is not there, items carrying both decimals and precision. Namespace
declarations are worked out from the QNames actually used, so you only declare
a prefix when you care which one it is.
Output is deterministic. The same document always produces the same bytes, and contexts, units and facts are written in document order — filers regenerate and diff their filings, so stable output matters.
What The Library Parses
- Contexts, including entity identifiers, periods, segments, and scenarios
- Units, including simple and divide units with resolved measure QNames
- Facts as typed items and tuples
- Schema, linkbase, role, and arcrole references
- Footnote links, locators, resources, and arcs
- Namespace declarations from the root instance element
Design Notes
parseXbrl(xml)returns anXbrlInstanceornull- Element and measure names are resolved into
{ namespace, localName, prefix } - Fact values stay as strings so callers can apply their own numeric and precision rules
- Contexts and units are indexed by ID for direct lookup from fact references
- Segment and scenario dimensions are parsed into structured members when possible
API Reference
Detailed API documentation lives in docs/api_reference.md.
Development
This repo uses Bun and the oxc toolchain: oxlint, oxfmt, and tsdown (rolldown-powered bundler).
bun run test # run tests once (vitest)
bun run test:watch # run tests in watch mode
bun run lint # oxlint
bun run format # oxfmt
bun run typecheck # tsc --noEmit
bun run build # bundle to dist/ with tsdown
bun run ci # typecheck + lint + test + buildLicense
MIT
