Introduction
Relevant source files
The following files were used as context for generating this wiki page:
@cellarnode/beverage-utils is a TypeScript library providing classification utilities for the CellarNode platform. It facilitates the mapping, formatting, and normalization of beverage data according to industry-standard classification systems, including support for HS headings and OIV types. The library is designed to work across any JavaScript environment with specific adapters for React, Vue, and Angular frameworks.
Sources: README.md:1-12, src/types.ts:1-17
The core functionality revolves around resolving "composite keys" to handle overlapping subtype IDs across different categories (e.g., "Red" under Still Wine vs. "Red" under Sparkling Wine). It also provides robust normalization for tokens, country codes, and liquid volumes to ensure data consistency across diverse beverage datasets.
Sources: README.md:20-27, src/normalize.ts:1-115
Core Architecture and Data Modeling
The system is built around a hierarchical classification structure where categories contain multiple subtypes.
Data Structures
The primary data model consists of three main interfaces that define the shape of the classification data retrieved from the CellarNode API.
| Interface | Description | Key Fields |
|---|---|---|
BeverageSubtype | Represents a specific variety of beverage. | id, name, oivType |
BeverageCategory | Represents a broad group of beverages. | id, name, hsHeading, subtypes |
BeverageClassification | The root container for all categories. | categories |
Sources: src/types.ts:1-17
Classification Hierarchy
The following diagram illustrates the relationship between categories and subtypes within the classification system.
Sources: src/types.ts:1-17
Label Mapping and Disambiguation
A central feature of the library is the buildLabelMap function, which converts the hierarchical classification data into a flat LabelMap for efficient lookups.
Composite Key Logic
To prevent collisions where different categories use identical subtype IDs, the map generates three types of keys:
- Category ID: Maps directly to the category name.
- Subtype ID: Maps to the subtype name (last-write-wins if duplicates exist).
- Composite Key: Uses the format
category:subtypeto ensure unambiguous lookup.
Sources: README.md:32-44, src/label-map.ts:5-14
Formatting Logic
The library provides two primary formatting functions in src/format.ts:
formatBeverageLabel: Looks up a key in the map or humanizes a snake_case slug as a fallback.formatBeverageType: Combines a category and subtype into a display string (e.g., "Still Wine / Red Wine").
Sources: src/format.ts:3-23
Data Normalization
The src/normalize.ts module provides utilities for standardizing free-text input into canonical formats.
Normalization Pipeline
The library handles three main types of normalization:
- Token Normalization: Trims whitespace, removes diacritics (accents), and converts strings to lowercase hyphenated slugs.
- Country Resolution: Resolves country names or ISO codes (alpha-2/3) to canonical ISO alpha-2 codes using
i18n-iso-countries. - Volume Parsing: Converts various volume strings (e.g., "750ml", "20 hl", "bottles 750ml x 4000") into a numeric liter value.
Sources: src/normalize.ts:7-115
Sources: src/normalize.ts:1-115
Framework Integration
Integration with React, Vue, and Angular is achieved via framework-specific adapters that utilize TanStack Query.
Data Flow for Frameworks
All adapters follow a similar pattern for fetching and caching classification data.
Query Configuration
The adapters use a staleTime of Infinity because beverage classification data is considered static and rarely changes during a session.
Sources: src/react/use-beverage-label-map.ts:19, src/vue/use-beverage-label-map.ts:19, src/angular/beverage-label-map.service.ts:19
Conclusion
@cellarnode/beverage-utils provides a robust foundation for handling beverage classification data. By combining a flexible hierarchical data model with flat, disambiguated lookup maps and comprehensive normalization utilities, it ensures consistent display and processing of beverage information across diverse technology stacks.