Skip to content

Commit 7ddd75b

Browse files
committed
doc: add readme
1 parent e8def76 commit 7ddd75b

File tree

1 file changed

+375
-1
lines changed

1 file changed

+375
-1
lines changed

packages/jsonld-tools/README.md

Lines changed: 375 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,375 @@
1-
# jsonldjs
1+
# `jsonldjs`
2+
3+
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.
4+
5+
## Installation
6+
7+
```bash
8+
# Using pnpm (recommended)
9+
pnpm add jsonldjs
10+
11+
# Using npm
12+
npm install jsonldjs
13+
14+
# Using yarn
15+
yarn add jsonldjs
16+
```
17+
18+
## Features
19+
20+
- **Configuration-First Design**: Separate immutable configuration from graph processing for maximum flexibility
21+
- **Fluent Interface**: Chainable methods for building complex filtering logic
22+
- **Property-Level Filtering**: Filter properties by entity IDs or types
23+
- **Subgraph Extraction**: Extract connected subgraphs with reference following
24+
- **Runtime Overrides**: Apply configuration and then override at runtime
25+
- **Type Safety**: Full TypeScript support with proper type inference
26+
- **Extensibility**: Custom pipes and transformation functions
27+
28+
## Quick Start
29+
30+
### Basic Usage
31+
32+
```typescript
33+
import { createJsonLdBuilder } from 'jsonldjs';
34+
import { jsonldGraph } from '@/data/jsonld';
35+
36+
// Simple filtering
37+
const result = createJsonLdBuilder()
38+
.baseGraph(jsonldGraph)
39+
.includeTypes(['Organization', 'Person'])
40+
.excludeTypes(['ImageObject'])
41+
.maxEntities(10)
42+
.build({
43+
prettyPrint: true,
44+
withScriptTag: true,
45+
scriptId: 'json-ld',
46+
});
47+
```
48+
49+
### Configuration-First Approach
50+
51+
```typescript
52+
import { createJsonLdBuilder, createJsonLdConfig } from 'jsonldjs';
53+
54+
// Create reusable configurations
55+
const globalConfig = createJsonLdConfig()
56+
.baseGraph(jsonldGraph)
57+
.includeIds(['org:hyperweb', 'website:hyperweb.io'])
58+
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] });
59+
60+
// Extend configurations immutably
61+
const homeConfig = globalConfig.excludeTypes(['ImageObject']);
62+
const blogConfig = globalConfig.includeTypes(['Article']);
63+
64+
// Use configurations
65+
const result = createJsonLdBuilder()
66+
.applyConfig(homeConfig)
67+
.excludeIds(['runtime:override']) // Runtime overrides
68+
.build({ prettyPrint: true });
69+
```
70+
71+
## Configuration Merging Behavior
72+
73+
### Default Merging
74+
75+
All configuration methods **merge by default** instead of replacing. This provides predictable behavior across all methods:
76+
77+
```typescript
78+
const config = createJsonLdConfig()
79+
.includeIds(['a', 'b'])
80+
.includeIds(['c', 'd']) // Result: ['a', 'b', 'c', 'd']
81+
.includeTypes(['Person'])
82+
.includeTypes(['Organization']); // Result: ['Person', 'Organization']
83+
```
84+
85+
### Clear Methods
86+
87+
When you need to replace instead of merge, use the clear methods:
88+
89+
```typescript
90+
const config = createJsonLdConfig()
91+
.includeIds(['old1', 'old2'])
92+
.clearIds() // Clear both includeIds and excludeIds
93+
.includeIds(['new1', 'new2']); // Result: ['new1', 'new2']
94+
```
95+
96+
#### Available Clear Methods
97+
98+
- `clearIds()` - Clears both `includeIds` and `excludeIds`
99+
- `clearTypes()` - Clears both `includeTypes` and `excludeTypes`
100+
- `clearPropertyRequirements()` - Clears both `requiredProperties` and `excludeEntitiesWithProperties`
101+
- `clearPropertyFilters()` - Clears both `propertyFiltersByIds` and `propertyFiltersByTypes`
102+
- `clearSubgraph()` - Clears `subgraphRoots`
103+
- `clearAll()` - Clears entire configuration (except `baseGraph`)
104+
105+
## API Reference
106+
107+
### Factory Functions
108+
109+
#### `createJsonLdConfig()`
110+
111+
Creates a new immutable configuration builder.
112+
113+
```typescript
114+
const config = createJsonLdConfig()
115+
.baseGraph(graph)
116+
.includeIds(['org:hyperweb'])
117+
.excludeTypes(['ImageObject']);
118+
```
119+
120+
#### `createJsonLdBuilder()`
121+
122+
Creates a new builder that extends the configuration builder with graph processing capabilities.
123+
124+
```typescript
125+
const builder = createJsonLdBuilder().baseGraph(graph).applyConfig(config);
126+
```
127+
128+
### Configuration Methods
129+
130+
All methods are inherited by the builder from the configuration builder:
131+
132+
#### Entity Filtering
133+
134+
- `.includeIds(ids: string[])` - Include entities with these IDs (merges with existing)
135+
- `.excludeIds(ids: string[])` - Exclude entities with these IDs (merges with existing)
136+
- `.includeTypes(types: string[])` - Include these entity types (merges with existing)
137+
- `.excludeTypes(types: string[])` - Exclude these entity types (merges with existing)
138+
- `.customFilter(fn: JsonLdFilter)` - Apply custom filter function
139+
- `.maxEntities(max: number)` - Limit maximum number of entities
140+
- `.requiredProperties(props: string[])` - Include entities with these properties (merges with existing)
141+
- `.excludeEntitiesWithProperties(props: string[])` - Exclude entities with these properties (merges with existing)
142+
143+
#### Clear Methods
144+
145+
- `.clearIds()` - Clear both includeIds and excludeIds
146+
- `.clearTypes()` - Clear both includeTypes and excludeTypes
147+
- `.clearPropertyRequirements()` - Clear both requiredProperties and excludeEntitiesWithProperties
148+
- `.clearPropertyFilters()` - Clear both propertyFiltersByIds and propertyFiltersByTypes
149+
- `.clearSubgraph()` - Clear subgraphRoots
150+
- `.clearAll()` - Clear entire configuration (except baseGraph)
151+
152+
#### Property Filtering
153+
154+
- `.filterPropertiesByIds(entityIds, rule)` - Filter properties for specific entity IDs
155+
- `.filterPropertiesByTypes(entityTypes, rule)` - Filter properties for specific entity types
156+
157+
```typescript
158+
// Filter properties by entity ID
159+
.filterPropertiesByIds(['org:hyperweb'], {
160+
exclude: ['subjectOf', 'member']
161+
})
162+
163+
// Filter properties by entity type
164+
.filterPropertiesByTypes(['Article'], {
165+
include: ['headline', 'author', 'datePublished']
166+
})
167+
```
168+
169+
#### Graph Operations
170+
171+
- `.baseGraph(graph: JsonLdGraph)` - Set the base graph to process
172+
- `.subgraph(rootIds: string[])` - Extract subgraph starting from these root IDs
173+
- `.addEntities(entities: JsonLdEntity[])` - Add additional entities
174+
- `.pipe(fn: PipeFunction)` - Add custom transformation function
175+
176+
#### Builder-Only Methods
177+
178+
- `.applyConfig(config: JsonLdConfig)` - Apply a pre-built configuration
179+
- `.getCurrentGraph()` - Get the current graph state
180+
- `.build(options?: BuildOptions)` - Build the final JSON-LD output
181+
182+
### Build Options
183+
184+
```typescript
185+
interface BuildOptions {
186+
prettyPrint?: boolean; // Pretty-print JSON output (default: true)
187+
contextUrl?: string; // Custom context URL (default: 'https://schema.org')
188+
withScriptTag?: boolean; // Wrap in script tag (default: false)
189+
scriptId?: string; // Script tag ID
190+
}
191+
```
192+
193+
## Advanced Usage
194+
195+
### Complex Filtering Logic
196+
197+
The builder implements three distinct filtering paths based on configuration:
198+
199+
1. **Subgraph Mode**: When `subgraph()` is used, property filtering is applied during traversal
200+
2. **IncludeIds Mode**: When `includeIds()` is used, entities are filtered first, then additional filters applied
201+
3. **Global Mode**: Property filtering is applied first, then entity filtering
202+
203+
```typescript
204+
// Subgraph mode - follows references with property filtering
205+
const result = createJsonLdBuilder()
206+
.baseGraph(graph)
207+
.subgraph(['org:hyperweb'])
208+
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] })
209+
.build();
210+
211+
// IncludeIds mode - simple entity filtering
212+
const result = createJsonLdBuilder()
213+
.baseGraph(graph)
214+
.includeIds(['org:hyperweb', 'person:john'])
215+
.excludeTypes(['ImageObject'])
216+
.build();
217+
```
218+
219+
### Custom Transformations
220+
221+
```typescript
222+
const result = createJsonLdBuilder()
223+
.baseGraph(graph)
224+
.includeTypes(['Person'])
225+
.pipe((graph) =>
226+
graph.map((entity) => ({
227+
...entity,
228+
processed: true,
229+
}))
230+
)
231+
.pipe((graph) => graph.filter((entity) => entity.name))
232+
.build();
233+
```
234+
235+
### Configuration Reuse
236+
237+
```typescript
238+
// Base configuration
239+
const baseConfig = createJsonLdConfig()
240+
.baseGraph(jsonldGraph)
241+
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] });
242+
243+
// Page-specific configurations
244+
const homeConfig = baseConfig.excludeTypes(['ImageObject']);
245+
const blogConfig = baseConfig.includeTypes(['Article']);
246+
const personConfig = baseConfig.includeTypes(['Person', 'Organization']);
247+
248+
// Use with different base graphs
249+
const articlesConfig = baseConfig.baseGraph(articlesGraph);
250+
```
251+
252+
## Options Processing Order
253+
254+
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.
255+
256+
### Processing Layers
257+
258+
The builder processes options in the following sequential layers:
259+
260+
#### 1. **Configuration Validation**
261+
262+
- Validates that a base graph is provided
263+
- Checks for critical configuration errors that would break processing
264+
- Throws errors if validation fails
265+
266+
#### 2. **Subgraph Extraction** (Layer 1)
267+
268+
- **Condition**: Only when `subgraphRoots` are configured via `.subgraph(rootIds)`
269+
- **Process**: Extracts connected subgraphs starting from root entities
270+
- **Property Filtering**: Applied **during** subgraph traversal for optimal performance
271+
- **Result**: Property filters are marked as applied to avoid duplicate processing
272+
273+
```typescript
274+
// Example: Subgraph extraction with property filtering
275+
const result = createJsonLdBuilder()
276+
.baseGraph(graph)
277+
.subgraph(['org:hyperweb']) // Layer 1: Extract subgraph
278+
.filterPropertiesByIds(['org:hyperweb'], { exclude: ['subjectOf'] }) // Applied during traversal
279+
.build();
280+
```
281+
282+
#### 3. **Entity and Property Filtering** (Layer 2)
283+
284+
- **Condition**: When entity filters are configured (includeIds, excludeIds, includeTypes, etc.)
285+
- **Sub-step 3a - Property Filtering**: Applied first if not already done in Layer 1
286+
- Filters properties based on entity IDs or types
287+
- Uses `filterGraphProperties()` function
288+
- **Sub-step 3b - Entity Filtering**: Applied after property filtering
289+
- Filters entire entities based on ID, type, and other criteria
290+
- Uses `filterJsonLdGraph()` function
291+
292+
```typescript
293+
// Example: Property filtering followed by entity filtering
294+
const result = createJsonLdBuilder()
295+
.baseGraph(graph)
296+
.filterPropertiesByTypes(['Article'], { include: ['headline', 'author'] }) // 3a: Property filtering
297+
.includeTypes(['Article', 'Person']) // 3b: Entity filtering
298+
.excludeIds(['unwanted:id']) // 3b: Additional entity filtering
299+
.build();
300+
```
301+
302+
#### 4. **Entity Population**
303+
304+
- **Condition**: When `populateConfig` is set
305+
- **Process**: Applies population rules to add related entities
306+
- **Function**: Uses `applyPopulateConfig()`
307+
308+
#### 5. **Additional Entities**
309+
310+
- **Condition**: When additional entities are specified via `.addEntities()`
311+
- **Process**: Appends additional entities to the graph
312+
- **Note**: These entities bypass all previous filtering
313+
314+
#### 6. **Custom Transformation Pipes**
315+
316+
- **Condition**: When custom pipes are added via `.pipe(fn)`
317+
- **Process**: Applies custom transformation functions in the order they were added
318+
- **Note**: This is the final processing step before output
319+
320+
```typescript
321+
// Example: Custom pipes applied last
322+
const result = createJsonLdBuilder()
323+
.baseGraph(graph)
324+
.includeTypes(['Person'])
325+
.pipe((graph) => graph.map((entity) => ({ ...entity, processed: true }))) // Applied last
326+
.pipe((graph) => graph.filter((entity) => entity.name)) // Applied after previous pipe
327+
.build();
328+
```
329+
330+
### Key Processing Rules
331+
332+
1. **Property Filters Before Entity Filters**: Property filtering always happens before entity filtering (except in subgraph mode where they're combined)
333+
334+
2. **Subgraph Mode Optimization**: When using subgraphs, property filtering is applied during traversal for better performance
335+
336+
3. **Single Property Filter Application**: Property filters are only applied once to avoid duplicate processing
337+
338+
4. **Additive Additional Entities**: Entities added via `.addEntities()` are appended after all filtering
339+
340+
5. **Sequential Pipe Execution**: Custom pipes are executed in the order they were added
341+
342+
## Performance Considerations
343+
344+
- **Immutable Configurations**: Each configuration method returns a new object, enabling safe reuse
345+
- **Lazy Evaluation**: Graph processing only occurs when `build()` or `getCurrentGraph()` is called
346+
- **Efficient Filtering**: Uses optimized filtering paths based on configuration type
347+
- **Memory Management**: Avoids unnecessary intermediate copies of large graphs
348+
349+
## Development
350+
351+
### Prerequisites
352+
353+
- Node.js 16+
354+
- pnpm (recommended package manager)
355+
356+
### Setup
357+
358+
1. Clone the repository:
359+
360+
```bash
361+
git clone https://github.com/hyperweb-io/jsonld-tools.git
362+
cd jsonld-tools
363+
```
364+
365+
2. Install dependencies:
366+
367+
```bash
368+
pnpm install
369+
```
370+
371+
3. Build the project:
372+
373+
```bash
374+
pnpm run build
375+
```

0 commit comments

Comments
 (0)