jsonldjs
A powerful, generic JSON-LD builder with comprehensive entity and property filtering capabilities. Provides both immutable configuration building and mutable graph processing with a fluent interface.
Installation
pnpm add jsonldjs
npm install jsonldjs
yarn add jsonldjs
Features
- Configuration-First Design: Separate immutable configuration from graph processing for maximum flexibility
- Fluent Interface: Chainable methods for building complex filtering logic
- Property-Level Filtering: Filter properties by entity IDs or types
- Subgraph Extraction: Extract connected subgraphs with reference following
- Runtime Overrides: Apply configuration and then override at runtime
- Type Safety: Full TypeScript support with proper type inference
- Extensibility: Custom pipes and transformation functions
Quick Start
Basic Usage
import { createJsonLdBuilder } from 'jsonldjs';
import { jsonldGraph } from '@/data/jsonld';
const result = createJsonLdBuilder()
.baseGraph(jsonldGraph)
.includeTypes(['Organization', 'Person'])
.excludeTypes(['ImageObject'])
.maxEntities(10)
.build({
prettyPrint: true,
withScriptTag: true,
scriptId: 'json-ld',
});
Configuration-First Approach
import { createJsonLdBuilder, createJsonLdConfig } from 'jsonldjs';
const globalConfig = createJsonLdConfig()
.baseGraph(jsonldGraph)
.includeIds(['org:hyperweb', 'website:hyperweb.io'])
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] });
const homeConfig = globalConfig.excludeTypes(['ImageObject']);
const blogConfig = globalConfig.includeTypes(['Article']);
const result = createJsonLdBuilder()
.mergeConfig(homeConfig.getConfig())
.excludeIds(['runtime:override'])
.build({ prettyPrint: true });
Configuration Merging Behavior
Default Merging
All configuration methods merge by default instead of replacing. This provides predictable behavior across all methods:
const config = createJsonLdConfig()
.includeIds(['a', 'b'])
.includeIds(['c', 'd'])
.includeTypes(['Person'])
.includeTypes(['Organization']);
Clear Methods
When you need to replace instead of merge, use the clear methods:
const config = createJsonLdConfig()
.includeIds(['old1', 'old2'])
.clearIds()
.includeIds(['new1', 'new2']);
Available Clear Methods
clearIds()
- Clears both includeIds
and excludeIds
clearTypes()
- Clears both includeTypes
and excludeTypes
clearPropertyRequirements()
- Clears both requiredProperties
and excludeEntitiesWithProperties
clearPropertyFilters()
- Clears both propertyFiltersByIds
and propertyFiltersByTypes
clearSubgraph()
- Clears subgraphRoots
clearAll()
- Clears entire configuration (except baseGraph
)
API Reference
Factory Functions
createJsonLdConfig()
Creates a new immutable configuration builder.
const config = createJsonLdConfig()
.baseGraph(graph)
.includeIds(['org:hyperweb'])
.excludeTypes(['ImageObject']);
createJsonLdBuilder()
Creates a new builder that extends the configuration builder with graph processing capabilities.
const builder = createJsonLdBuilder().baseGraph(graph).mergeConfig(config);
Configuration Methods
All methods are inherited by the builder from the configuration builder:
Entity Filtering
.includeIds(ids: string[])
- Include entities with these IDs (merges with existing)
.excludeIds(ids: string[])
- Exclude entities with these IDs (merges with existing)
.includeTypes(types: string[])
- Include these entity types (merges with existing)
.excludeTypes(types: string[])
- Exclude these entity types (merges with existing)
.customFilter(fn: JsonLdFilter)
- Apply custom filter function
.maxEntities(max: number)
- Limit maximum number of entities
.requiredProperties(props: string[])
- Include entities with these properties (merges with existing)
.excludeEntitiesWithProperties(props: string[])
- Exclude entities with these properties (merges with existing)
Clear Methods
.clearIds()
- Clear both includeIds and excludeIds
.clearTypes()
- Clear both includeTypes and excludeTypes
.clearPropertyRequirements()
- Clear both requiredProperties and excludeEntitiesWithProperties
.clearPropertyFilters()
- Clear both propertyFiltersByIds and propertyFiltersByTypes
.clearSubgraph()
- Clear subgraphRoots
.clearAll()
- Clear entire configuration (except baseGraph)
Configuration Merging
.mergeConfig(config: JsonLdConfig)
- Merge with another complete configuration
.mergeFilters(filters: JsonLdFilterOptions)
- Merge only the filters part of another configuration
Available in both config builder and main builder - These methods work the same way in both classes.
const baseConfig = createJsonLdConfig().includeTypes(['Person']);
const otherConfig = createJsonLdConfig()
.includeTypes(['Organization'])
.excludeIds(['test'])
.getConfig();
const merged = baseConfig.mergeConfig(otherConfig);
const result = createJsonLdBuilder()
.baseGraph(graph)
.includeTypes(['Person'])
.mergeConfig(otherConfig)
.build({ prettyPrint: true });
const baseConfig = createJsonLdConfig().includeTypes(['Person']).addEntities([entity]);
const otherFilters = { includeTypes: ['Organization'], maxEntities: 10 };
const merged = baseConfig.mergeFilters(otherFilters);
Property Filtering
.filterPropertiesByIds(entityIds, rule)
- Filter properties for specific entity IDs
.filterPropertiesByTypes(entityTypes, rule)
- Filter properties for specific entity types
.filterPropertiesByIds(['org:hyperweb'], {
exclude: ['subjectOf', 'member']
})
.filterPropertiesByTypes(['Article'], {
include: ['headline', 'author', 'datePublished']
})
Graph Operations
.baseGraph(graph: JsonLdGraph)
- Set the base graph to process
.subgraph(rootIds: string[])
- Extract subgraph starting from these root IDs
.addEntities(entities: JsonLdEntity[])
- Add additional entities
.pipe(fn: PipeFunction)
- Add custom transformation function
Builder-Only Methods
.getCurrentGraph()
- Get the current graph state
.build(options?: BuildOptions)
- Build the final JSON-LD output
Build Options
interface BuildOptions {
prettyPrint?: boolean;
contextUrl?: string;
withScriptTag?: boolean;
scriptId?: string;
}
Advanced Usage
Complex Filtering Logic
The builder implements three distinct filtering paths based on configuration:
- Subgraph Mode: When
subgraph()
is used, property filtering is applied during traversal
- IncludeIds Mode: When
includeIds()
is used, entities are filtered first, then additional filters applied
- Global Mode: Property filtering is applied first, then entity filtering
const result = createJsonLdBuilder()
.baseGraph(graph)
.subgraph(['org:hyperweb'])
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] })
.build();
const result = createJsonLdBuilder()
.baseGraph(graph)
.includeIds(['org:hyperweb', 'person:john'])
.excludeTypes(['ImageObject'])
.build();
Custom Transformations
const result = createJsonLdBuilder()
.baseGraph(graph)
.includeTypes(['Person'])
.pipe((graph) =>
graph.map((entity) => ({
...entity,
processed: true,
}))
)
.pipe((graph) => graph.filter((entity) => entity.name))
.build();
Configuration Reuse
const baseConfig = createJsonLdConfig()
.baseGraph(jsonldGraph)
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] });
const homeConfig = baseConfig.excludeTypes(['ImageObject']);
const blogConfig = baseConfig.includeTypes(['Article']);
const personConfig = baseConfig.includeTypes(['Person', 'Organization']);
const articlesConfig = baseConfig.baseGraph(articlesGraph);
Options Processing Order
The JSON-LD builder processes options in a specific order defined by the processGraph
method. Understanding this order is crucial for predicting the final output when multiple filtering options are applied.
Processing Layers
The builder processes options in the following sequential layers:
1. Configuration Validation
- Validates that a base graph is provided
- Checks for critical configuration errors that would break processing
- Throws errors if validation fails
- Condition: Only when
subgraphRoots
are configured via .subgraph(rootIds)
- Process: Extracts connected subgraphs starting from root entities
- Property Filtering: Applied during subgraph traversal for optimal performance
- Result: Property filters are marked as applied to avoid duplicate processing
const result = createJsonLdBuilder()
.baseGraph(graph)
.subgraph(['org:hyperweb'])
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] })
.build();
3. Entity and Property Filtering (Layer 2)
- Condition: When entity filters are configured (includeIds, excludeIds, includeTypes, etc.)
- Sub-step 3a - Property Filtering: Applied first if not already done in Layer 1
- Filters properties based on entity IDs or types
- Uses
filterGraphProperties()
function
- Sub-step 3b - Entity Filtering: Applied after property filtering
- Filters entire entities based on ID, type, and other criteria
- Uses
filterJsonLdGraph()
function
const result = createJsonLdBuilder()
.baseGraph(graph)
.filterPropertiesByTypes(['Article'], { include: ['headline', 'author'] })
.includeTypes(['Article', 'Person'])
.excludeIds(['unwanted:id'])
.build();
4. Entity Population
- Condition: When
populateConfig
is set
- Process: Applies population rules to add related entities
- Function: Uses
applyPopulateConfig()
5. Additional Entities
- Condition: When additional entities are specified via
.addEntities()
- Process: Appends additional entities to the graph
- Note: These entities bypass all previous filtering
6. Custom Transformation Pipes
- Condition: When custom pipes are added via
.pipe(fn)
- Process: Applies custom transformation functions in the order they were added
- Note: This is the final processing step before output
const result = createJsonLdBuilder()
.baseGraph(graph)
.includeTypes(['Person'])
.pipe((graph) => graph.map((entity) => ({ ...entity, processed: true })))
.pipe((graph) => graph.filter((entity) => entity.name))
.build();
Key Processing Rules
-
Property Filters Before Entity Filters: Property filtering always happens before entity filtering (except in subgraph mode where they're combined)
-
Subgraph Mode Optimization: When using subgraphs, property filtering is applied during traversal for better performance
-
Single Property Filter Application: Property filters are only applied once to avoid duplicate processing
-
Additive Additional Entities: Entities added via .addEntities()
are appended after all filtering
-
Sequential Pipe Execution: Custom pipes are executed in the order they were added
Performance Considerations
- Immutable Configurations: Each configuration method returns a new object, enabling safe reuse
- Lazy Evaluation: Graph processing only occurs when
build()
or getCurrentGraph()
is called
- Efficient Filtering: Uses optimized filtering paths based on configuration type
- Memory Management: Avoids unnecessary intermediate copies of large graphs
Development
Prerequisites
- Node.js 16+
- pnpm (recommended package manager)
Setup
git clone https://github.com/hyperweb-io/jsonld-tools.git
cd jsonld-tools
pnpm install
pnpm run build