npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bc3

v0.7.0

Published

Parser and hierarchical model for FIEBDC-3 BC3 files.

Readme

BC3

BC3 is an open-source TypeScript library for parsing and modeling FIEBDC-3 / BC3 construction database files.

It provides a structured parsing pipeline and a hierarchical object model representing a BC3 document, allowing you to navigate concepts, decompositions, measurements, and relationships in a type-safe way.

Status

Active development — Core parsing and domain model are functional. API is stable for basic usage.

Current version: v0.6.0

Installation

npm install bc3

Quick Start

import { BC3 } from 'bc3';

// Parse a BC3 file
const bc3Text = `~V|RIB Spain|FIEBDC-3/2020\\02102025|Presto 25.00||...
~C|001010|h|CAPATAZ|29.11|020922|1|
...`;

const result = BC3.parse(bc3Text, { mode: 'lenient' });

Features

✅ Core Functionality

  • Full BC3 parsing: Supports all standard BC3 record types (~V, ~C, ~D, ~M, ~T, ~X, ~L, ~A, ~E, ~K)
  • Hierarchical model: Navigate concepts as a tree structure with parent-child relationships
  • Multiple occurrences: Handle concepts that appear multiple times in different branches
  • Decompositions: Access factor, performance (rendimiento), and percentage codes
  • Measurements: Parse measurement data with positions, totals, and details
  • Metadata: Extract document version, generator, dates, and properties
  • Diagnostics: Collect warnings and errors during parsing

API Reference

BC3.parse(input, options?)

Parses a BC3 text input and returns a structured result.

Parameters:

  • input (string): Raw BC3 text content
  • options (optional):
    • mode: 'strict' | 'lenient' (default: 'lenient')

Returns: ParseResult

interface ParseResult {
  document?: BC3Document; // The parsed document
  diagnostics: Diagnostic[]; // Warnings and errors
}

BC3Document

The main domain model representing a parsed BC3 file.

Key methods:

  • getConcept(code: string): Get a concept node by normalized code
  • countConceptOccurrences(code: string): Count how many times a concept appears in the tree
  • getAllPathsToConcept(code: string): Get all paths from root to a concept
  • getPathToConcept(code: string): Get the first path to a concept
  • getParentNodes(code: string): Get all parent nodes of a concept
  • getChildNodes(code: string): Get direct children of a concept
  • getDecompositionInfo(parentCode, childCode): Get decomposition data (performance, factor)
  • getHierarchySummary(): Get statistics about the tree structure

Properties:

  • roots: ConceptNode[]: Root nodes of the hierarchy
  • conceptsByCode: Map<string, ConceptNode>: Lookup map for all concepts
  • metadata?: DocumentMetadata: Document metadata from ~V record
  • entities: Map<string, Entity>: Parsed entities
  • specificationsDictionary?: Specification: Specifications dictionary
  • itCodesDictionary?: ITCodes: IT codes dictionary

ConceptNode

Represents a node in the hierarchical BC3 structure.

Properties:

  • concept: Concept: The concept data (code, unit, summary, prices, dates, etc.)
  • children: ConceptNode[]: Direct child nodes
  • decompositions: Decomposition[]: Decomposition relationships
  • measurements: Measurement[]: Associated measurements
  • attachments: Attachment[]: Linked attachments

Examples

Navigate the hierarchy

const result = BC3.parse(bc3Text);
const document = result.document;

if (document) {
  // Walk the tree
  document.walkTree((node, depth) => {
    const indent = '  '.repeat(depth);
    console.log(`${indent}${node.concept.codeNorm} - ${node.concept.summary}`);
  });

  // Get hierarchy summary
  const summary = document.getHierarchySummary();
  console.log(`Total nodes: ${summary.totalNodes}`);
  console.log(`Max depth: ${summary.maxDepth}`);
}

Find concept occurrences

const code = '001010';
const occurrences = document.countConceptOccurrences(code);
console.log(`Concept ${code} appears ${occurrences} times`);

// Get all paths to the concept
const paths = document.getAllPathsToConcept(code);
paths.forEach((path, idx) => {
  console.log(
    `Path ${idx + 1}: ${path.map((n) => n.concept.codeNorm).join(' → ')}`,
  );
});

Access decomposition data

const parentCode = '300100';
const childCode = '001010';

const decompInfo = document.getDecompositionInfo(parentCode, childCode);
if (decompInfo) {
  console.log(`Performance: ${decompInfo.performance}`);
  console.log(`Factor: ${decompInfo.factor}`);

  // Calculate amount
  const child = document.getConcept(childCode);
  if (child && child.concept.prices.length > 0) {
    const price = child.concept.prices[child.concept.prices.length - 1];
    const amount = price * (decompInfo.performance || 0);
    console.log(`Amount: ${formatPrice(amount)}`);
  }
}

Parsing Modes

Lenient (default)

  • Continues parsing even when encountering errors
  • Collects diagnostics (warnings/errors) but doesn't throw
  • Best for production use when you want to handle partial data

Strict

  • Stops parsing on errors
  • Useful for validation and debugging
  • Throws structured exceptions with diagnostics

Architecture & Documentation

The core architecture and design decisions are documented in:

  • Grammar rules BC3 lexical rules: record delimiters, fields, subfields, and whitespace handling.

  • Domain model Core entities: BC3Document, Concept, Decomposition, Measurement, attachments.

  • Parsing modes Strict vs lenient parsing, warnings, errors, and diagnostics strategy.

  • Design patterns Builder, Strategy, and Composite responsibilities and interactions.

  • Module boundaries Folder structure, importers, parsing pipeline, and dependency rules.

  • Public API Public API contract, sync/async decisions, inputs, outputs, and extensibility.

Project Workflow

  • Development happens on develop
  • Each change is tracked via GitHub Issues and GitHub Projects
  • Versioning and releases are managed with Changesets
  • Publishing to npm is automated on merges to main

Roadmap

  • High-level roadmap and task breakdown are maintained in GitHub Projects
  • Each architectural decision is documented before implementation

License

MIT © Igor HC