mdld-parse 0.6.0 โ†’ 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,87 +4,86 @@
4
4
 
5
5
  [![NPM](https://img.shields.io/npm/v/mdld-parse)](https://www.npmjs.com/package/mdld-parse)
6
6
 
7
- [Documentation](https://mdld.js.org) | [Repository](https://github.com/davay42/mdld-parse) | [Playground](https://mdld.js.org/playground)
7
+ [Demo](https://mdld.js.org) | [Repository](https://github.com/davay42/mdld-parse)
8
8
 
9
- ## What is MD-LD?
9
+ ## ๐Ÿš€ Quick Start
10
10
 
11
- MD-LD allows you to author RDF graphs directly in Markdown using explicit `{...}` annotations:
12
-
13
- ```markdown
14
- [my] <tag:alice@example.com,2026:>
15
-
16
- # 2024-07-18 {=my:journal-2024-07-18 .my:Event my:date ^^xsd:date}
11
+ ```bash
12
+ pnpm install mdld-parse
13
+ ```
17
14
 
18
- ## A good day {label}
15
+ ```javascript
16
+ import { parse } from 'mdld-parse';
19
17
 
20
- Mood: [Happy] {my:mood}
21
- Energy level: [8] {my:energyLevel ^^xsd:integer}
18
+ const result = parse(`
19
+ [ex] <http://example.org/>
22
20
 
23
- Met [Sam] {+my:sam .my:Person ?my:attendee} on my regular walk at [Central Park] {+my:central-park ?my:location .my:Place label @en} and talked about [Sunny] {my:weather} weather.
21
+ # Document {=ex:doc .ex:Article label}
24
22
 
25
- Activities:
23
+ [Alice] {?ex:author =ex:alice .prov:Person ex:firstName label}
24
+ [Smith] {ex:lastName}`);
26
25
 
27
- - **Walking** {+ex:walking ?my:hasActivity .my:Activity label}
28
- - **Reading** {+ex:reading ?my:hasActivity .my:Activity label}
26
+ console.log(result.quads);
27
+ // RDF/JS quads ready for n3.js, rdflib, etc.
28
+ // @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
29
+ // @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
30
+ // @prefix prov: <http://www.w3.org/ns/prov#>.
31
+ // @prefix ex: <http://example.org/>.
29
32
 
33
+ // ex:doc a ex:Article;
34
+ // rdfs:label "Document";
35
+ // ex:author ex:alice.
36
+ // ex:alice a prov:Person;
37
+ // rdfs:label "Alice";
38
+ // ex:firstName "Alice";
39
+ // ex:lastName "Smith".
30
40
  ```
31
41
 
32
- Generates valid RDF triples:
33
-
34
- ```turtle
35
- @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
36
- @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
37
- @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
38
- @prefix sh: <http://www.w3.org/ns/shacl#>.
39
- @prefix prov: <http://www.w3.org/ns/prov#>.
40
- @prefix ex: <http://example.org/>.
41
- @prefix my: <tag:alice@example.com,2026:>.
42
-
43
- my:journal-2024-07-18 a my:Event;
44
- my:date "2024-07-18"^^xsd:date;
45
- rdfs:label "A good day";
46
- my:mood "Happy";
47
- my:energyLevel 8;
48
- my:attendee my:sam;
49
- my:location my:central-park;
50
- my:weather "Sunny";
51
- my:hasActivity <tag:alice@example.com,2026:journal-2024-07-18#walking>, <tag:alice@example.com,2026:journal-2024-07-18#reading>.
52
- my:sam a my:Person.
53
- my:central-park a my:Place;
54
- rdfs:label "Central Park"@en.
55
- <tag:alice@example.com,2026:journal-2024-07-18#walking> a my:Activity;
56
- rdfs:label "Walking".
57
- <tag:alice@example.com,2026:journal-2024-07-18#reading> a my:Activity;
58
- rdfs:label "Reading".
42
+ ## ๐Ÿ“š Documentation Hub
59
43
 
60
- ```
44
+ - **๐Ÿ“– [Documentation](./docs/index.md)** - Complete documentation with guides and references
45
+ - **๐ŸŽฏ [Examples](./examples/index.md)** - Real-world MD-LD examples and use cases
46
+ - **๐Ÿ“‹ [Specification](./spec/index.md)** - Formal specification and test suite
61
47
 
62
- Read the [FULL SPEC](./spec/Spec.md).
48
+ ## โœจ Core Features
63
49
 
64
- ## Core Features
50
+ - **๐Ÿ”— Prefix folding** - Build hierarchical namespaces with lightweight IRI authoring
51
+ - **๐Ÿ“ Subject declarations** - `{=IRI}` and `{=#fragment}` for context setting
52
+ - **๐ŸŽฏ Object IRIs** - `{+IRI}` and `{+#fragment}` for temporary object declarations
53
+ - **๐Ÿ”„ Three predicate forms** - `p` (Sโ†’L), `?p` (Sโ†’O), `!p` (Oโ†’S)
54
+ - **๐Ÿท๏ธ Type declarations** - `.Class` for rdf:type triples
55
+ - **๐Ÿ“… Datatypes & language** - `^^xsd:date` and `@en` support
56
+ - **๐Ÿงฉ Fragments** - Document structuring with `{=#fragment}`
57
+ - **โšก Polarity system** - Sophisticated diff authoring with `+` and `-` prefixes
58
+ - **๐Ÿ“ Origin tracking** - Complete provenance with lean quad-to-source mapping
65
59
 
66
- - **Prefix folding**: Build hierarchical namespaces with lightweight IRI authoring
67
- - **Subject declarations**: `{=IRI}` and `{=#fragment}` for context setting
68
- - **Object IRIs**: `{+IRI}` and `{+#fragment}` for temporary object declarations
69
- - **Four predicate forms**: `p` (Sโ†’L), `?p` (Sโ†’O), `!p` (Oโ†’S)
70
- - **Type declarations**: `.Class` for rdf:type triples
71
- - **Datatypes & language**: `^^xsd:date` and `@en` support
72
- - **Fragments**: Built-in document structuring with `{=#fragment}`
73
- - **Round-trip serialization**: Markdown โ†” RDF โ†” Markdown preserves structure
60
+ ## ๐ŸŒŸ What is MD-LD?
74
61
 
75
- ## Installation
62
+ MD-LD allows you to author RDF graphs directly in Markdown using explicit `{...}` annotations:
76
63
 
77
- ```bash
78
- npm install mdld-parse
64
+ ```markdown
65
+ [my] <tag:alice@example.com,2026:>
66
+ # 2024-07-18 {=my:journal-2024-07-18 .my:Event my:date ^^xsd:date}
67
+ ## A good day {label}
68
+ Mood: [Happy] {my:mood}
69
+ Energy level: [8] {my:energyLevel ^^xsd:integer}
70
+ Met [Sam] {+my:sam .my:Person ?my:attendee} on my regular walk at [Central Park] {+my:central-park ?my:location .my:Place label @en} and talked about [Sunny] {my:weather} weather.
79
71
  ```
80
72
 
73
+ Generates valid RDF triples with complete provenance tracking.
74
+
75
+ ## ๐Ÿ“ฆ Installation
76
+
81
77
  ### Node.js
82
78
 
79
+ ```bash
80
+ pnpm install mdld-parse
81
+ ```
82
+
83
83
  ```javascript
84
84
  import { parse } from 'mdld-parse';
85
85
 
86
86
  const markdown = `# Document {=ex:doc .Article}
87
-
88
87
  [Alice] {author}`;
89
88
 
90
89
  const result = parse(markdown, {
@@ -101,11 +100,11 @@ console.log(result.quads);
101
100
  <script type="module">
102
101
  import { parse } from 'https://cdn.jsdelivr.net/npm/mdld-parse/+esm';
103
102
 
104
- const result = parse('# Hello {=ex:hello}');
103
+ const result = parse('# Hello {=ex:hello label}');
105
104
  </script>
106
105
  ```
107
106
 
108
- ## Semantic Model
107
+ ## ๐Ÿง  Semantic Model
109
108
 
110
109
  MD-LD encodes a directed labeled multigraph where three nodes may be in scope:
111
110
 
@@ -123,399 +122,130 @@ Each predicate form determines the graph edge:
123
122
  | `?p` | S โ†’ O | `[NASA] {=ex:nasa ?org}` | object property |
124
123
  | `!p` | O โ†’ S | `[Parent] {=ex:p !hasPart}` | reverse object |
125
124
 
126
- ## Syntax Reference
125
+ ## ๐ŸŽจ Syntax Quick Reference
127
126
 
128
127
  ### Subject Declaration
129
-
130
128
  Set current subject (emits no quads):
131
-
132
129
  ```markdown
133
130
  ## Apollo 11 {=ex:apollo11}
134
131
  ```
135
132
 
136
- #### Fragment Syntax
137
-
133
+ ### Fragment Syntax
138
134
  Create fragment IRIs relative to current subject:
139
-
140
135
  ```markdown
141
136
  # Document {=ex:document}
142
137
  {=#summary}
143
138
  [Content] {label}
144
139
  ```
145
-
146
- ```turtle
147
- ex:document#summary rdfs:label "Content" .
148
- ```
149
-
150
140
  Fragments replace any existing fragment and require a current subject.
151
141
 
152
- Subject remains in scope until reset with `{=}` or new subject declared.
153
-
154
142
  ### Type Declaration
155
-
156
143
  Emit `rdf:type` triple:
157
-
158
144
  ```markdown
159
145
  ## Apollo 11 {=ex:apollo11 .ex:SpaceMission .ex:Event}
160
146
  ```
161
147
 
162
- ```turtle
163
- ex:apollo11 a ex:SpaceMission, ex:Event .
164
- ```
165
-
166
148
  ### Literal Properties
167
-
168
149
  Inline value carriers emit literal properties:
169
-
170
150
  ```markdown
171
151
  # Mission {=ex:apollo11}
172
-
173
152
  [Neil Armstrong] {ex:commander}
174
153
  [1969] {ex:year ^^xsd:gYear}
175
154
  [Historic mission] {ex:description @en}
176
155
  ```
177
156
 
178
- ```turtle
179
- ex:apollo11 ex:commander "Neil Armstrong" ;
180
- ex:year "1969"^^xsd:gYear ;
181
- ex:description "Historic mission"@en .
182
- ```
183
-
184
157
  ### Object Properties
185
-
186
158
  Links create relationships (use `?` prefix):
187
-
188
159
  ```markdown
189
160
  # Mission {=ex:apollo11}
190
-
191
161
  [NASA] {=ex:nasa ?ex:organizer}
192
162
  ```
193
163
 
194
- ```turtle
195
- ex:apollo11 ex:organizer ex:nasa .
196
- ```
197
-
198
164
  ### Resource Declaration
199
-
200
165
  Declare resources inline with `{=iri}`:
201
-
202
166
  ```markdown
203
167
  # Mission {=ex:apollo11}
204
-
205
168
  [Neil Armstrong] {=ex:armstrong ?ex:commander .prov:Person}
206
169
  ```
207
170
 
208
- ```turtle
209
- ex:apollo11 ex:commander ex:armstrong .
210
- ex:armstrong a prov:Person .
211
- ```
212
-
213
- ### Lists
214
-
215
- Lists are pure Markdown structure. Each list item requires explicit annotations:
216
-
217
- ```markdown
218
- # Recipe {=ex:recipe}
219
-
220
- Ingredients:
221
-
222
- - **Flour** {+ex:flour ?ex:ingredient .ex:Ingredient label}
223
- - **Water** {+ex:water ?ex:ingredient .ex:Ingredient label}
224
- ```
225
-
226
- ```turtle
227
- ex:recipe ex:ingredient ex:flour, ex:water .
228
- ex:flour a ex:Ingredient ; rdfs:label "Flour" .
229
- ex:water a ex:Ingredient ; rdfs:label "Water" .
230
- ```
231
-
232
- **Key Rules:**
233
- - No semantic propagation from list scope
234
- - Each item must have explicit annotations
235
- - Use `+IRI` to maintain subject chaining for repeated object properties
236
-
237
- ### Code Blocks
238
-
239
- Code blocks are value carriers:
240
-
241
- ````markdown
242
- # Example {=ex:example}
243
-
244
- ```javascript {=ex:code .ex:SoftwareSourceCode ex:text}
245
- console.log("hello");
246
- ```
247
- ````
248
-
249
- ```turtle
250
- ex:code a ex:SoftwareSourceCode ;
251
- ex:text "console.log(\"hello\")" .
252
- ```
253
-
254
- ### Blockquotes
255
-
256
- ```markdown
257
- # Article {=ex:article}
258
-
259
- > MD-LD bridges Markdown and RDF. {comment}
260
- ```
261
-
262
- ```turtle
263
- ex:article rdfs:comment "MD-LD bridges Markdown and RDF." .
264
- ```
265
-
266
- ### Reverse Relations
267
-
268
- Reverse the relationship direction:
269
-
270
- ```markdown
271
- # Part {=ex:part}
272
-
273
- Part of: {!ex:hasPart}
274
-
275
- - Book {=ex:book}
276
- ```
277
-
278
- ```turtle
279
- ex:book ex:hasPart ex:part .
280
- ```
281
-
282
- ### Prefix Declarations
283
-
284
- ```markdown
285
- [ex] <http://example.org/>
286
- [foaf] <http://xmlns.com/foaf/0.1/>
287
-
288
- # Person {=ex:alice .foaf:Person}
289
- ```
290
-
291
- ### Prefix Folding: Lightweight IRI Authoring
292
-
293
- Build hierarchical namespaces by referencing previously defined prefixes:
294
-
295
- ```markdown
296
- # Create your domain authority
297
- [my] <tag:mymail@domain.com,2026:>
298
-
299
- # Build namespace hierarchy
300
- [j] <my:journal:>
301
- [p] <my:property:>
302
- [c] <my:class:>
303
- [person] <my:people:>
304
-
305
- # Use in content
306
- # 2026-01-27 {=j:2026-01-27 .c:Event p:date ^^xsd:date}
307
-
308
- ## Harry {=person:harry p:name}
309
- ```
310
-
311
- **Resolves to absolute IRIs:**
312
- - `j:2026-01-27` โ†’ `tag:mymail@domain.com,2026:journal:2026-01-27`
313
- - `c:Event` โ†’ `tag:mymail@domain.com,2026:class:Event`
314
- - `p:date` โ†’ `tag:mymail@domain.com,2026:property:date`
315
- - `person:harry` โ†’ `tag:mymail@domain.com,2026:people:harry`
316
-
317
- **Benefits:**
318
- - **Lightweight**: No external ontology dependencies
319
- - **Domain authority**: Use `tag:` URIs for personal namespaces
320
- - **Hierarchical**: Build deep namespace structures
321
- - **Streaming-safe**: Forward-reference only, single-pass parsing
322
-
323
- ## API Reference
171
+ ## ๐Ÿ”ง API Reference
324
172
 
325
173
  ### `parse(markdown, options)`
326
174
 
327
- Parse MD-LD markdown and return RDF quads with origin tracking.
175
+ Parse MD-LD markdown and return RDF quads with lean origin tracking.
328
176
 
329
177
  **Parameters:**
330
-
331
178
  - `markdown` (string) โ€” MD-LD formatted text
332
179
  - `options` (object, optional):
333
180
  - `context` (object) โ€” Prefix mappings (default: `{ '@vocab': 'http://www.w3.org/2000/01/rdf-schema#', rdf, rdfs, xsd, sh, prov }`)
334
181
  - `dataFactory` (object) โ€” Custom RDF/JS DataFactory
335
182
 
336
- **Returns:** `{ quads, origin, context }`
183
+ **Returns:** `{ quads, remove, origin, context }`
337
184
 
338
- - `quads` โ€” Array of RDF/JS Quads
339
- - `origin` โ€” Origin tracking object with:
340
- - `blocks` โ€” Map of block IDs to source locations
341
- - `quadIndex` โ€” Map of quads to block IDs
185
+ - `quads` โ€” Array of RDF/JS Quads (final resolved graph state)
186
+ - `remove` โ€” Array of RDF/JS Quads (external retractions targeting prior state)
187
+ - `origin` โ€” Lean origin tracking object with quadIndex for UI navigation
342
188
  - `context` โ€” Final context used (includes prefixes)
343
189
 
344
- **Example:**
345
-
346
- ```javascript
347
- const result = parse(
348
- `# Article {=ex:article .ex:Article}
349
-
350
- [Alice] {=ex:alice ?author}`,
351
- { context: { ex: 'http://example.org/' } }
352
- );
353
-
354
- console.log(result.quads);
355
- // [
356
- // {
357
- // subject: { termType: 'NamedNode', value: 'http://example.org/article' },
358
- // predicate: { termType: 'NamedNode', value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' },
359
- // object: { termType: 'NamedNode', value: 'http://example.org/Article' }
360
- // },
361
- // ...
362
- // ]
363
- ```
364
-
365
- ### `applyDiff({ text, diff, origin, options })`
190
+ ### `merge(docs, options)`
366
191
 
367
- Apply RDF changes back to markdown with proper positioning.
192
+ Merge multiple MDLD documents with diff polarity resolution.
368
193
 
369
194
  **Parameters:**
370
-
371
- - `text` (string) โ€” Original markdown
372
- - `diff` (object) โ€” Changes to apply:
373
- - `add` (array) โ€” Quads to add
374
- - `delete` (array) โ€” Quads to remove
375
- - `origin` (object) โ€” Origin from `parse()` result
195
+ - `docs` (array) โ€” Array of markdown strings or ParseResult objects
376
196
  - `options` (object, optional):
377
- - `context` (object) โ€” Context for IRI shortening
378
-
379
- **Returns:** `{ text, origin }`
380
-
381
- - `text` โ€” Updated markdown
382
- - `origin` โ€” Updated origin tracking vacant slots
197
+ - `context` (object) โ€” Prefix mappings (merged with DEFAULT_CONTEXT)
383
198
 
384
- **Example:**
385
-
386
- ```javascript
387
- const original = `# Article {=ex:article}
388
-
389
- [Alice] {ex:author}`;
390
-
391
- const result = parse(original, { context: { ex: 'http://example.org/' } });
392
-
393
- // Add a new property
394
- const newQuad = {
395
- subject: { termType: 'NamedNode', value: 'http://example.org/article' },
396
- predicate: { termType: 'NamedNode', value: 'http://example.org/datePublished' },
397
- object: { termType: 'Literal', value: '2024-01-01' }
398
- };
399
-
400
- const updated = applyDiff({
401
- text: original,
402
- diff: { add: [newQuad] },
403
- origin: result.origin,
404
- options: { context: result.context }
405
- });
406
-
407
- console.log(updated.text);
408
- // # Article {=ex:article}
409
- //
410
- // [Alice] {author}
411
- // [2024-01-01] {datePublished}
412
- ```
199
+ **Returns:** `{ quads, remove, origin, context }`
413
200
 
414
201
  ### `generate(quads, context)`
415
202
 
416
- Generate deterministic MDLD from RDF quads with origin tracking.
203
+ Generate deterministic MDLD from RDF quads.
417
204
 
418
205
  **Parameters:**
419
-
420
206
  - `quads` (array) โ€” Array of RDF/JS Quads to convert
421
207
  - `context` (object, optional) โ€” Prefix mappings (default: `{}`)
422
- - Merged with DEFAULT_CONTEXT for proper CURIE shortening
423
- - Only user-defined prefixes are rendered in output
424
-
425
- **Returns:** `{ text, origin, context }`
426
-
427
- - `text` โ€” Generated MDLD markdown
428
- - `origin` โ€” Origin tracking object with:
429
- - `blocks` โ€” Map of block IDs to source locations
430
- - `quadIndex` โ€” Map of quads to block IDs
431
- - `context` โ€” Final context used (includes defaults)
432
208
 
433
- **Example:**
209
+ **Returns:** `{ text, context }`
434
210
 
435
- ```javascript
436
- const quads = [
437
- {
438
- subject: { termType: 'NamedNode', value: 'http://example.org/article' },
439
- predicate: { termType: 'NamedNode', value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' },
440
- object: { termType: 'NamedNode', value: 'http://example.org/Article' }
441
- },
442
- {
443
- subject: { termType: 'NamedNode', value: 'http://example.org/article' },
444
- predicate: { termType: 'NamedNode', value: 'http://example.org/author' },
445
- object: { termType: 'NamedNode', value: 'http://example.org/alice' }
446
- }
447
- ];
448
-
449
- const result = generate(quads, {
450
- ex: 'http://example.org/',
451
- });
452
-
453
- console.log(result.text);
454
- // # Article {=ex:article .ex:Article}
455
- //
456
- // > alice {+ex:alice ?ex:author}
457
- ```
458
-
459
- ### `locate(quad, origin, text, context)`
211
+ ### `locate(quad, origin)`
460
212
 
461
- Locate the precise text range of a quad in MDLD text using origin tracking.
213
+ Locate the origin entry for a quad using the lean origin system.
462
214
 
463
215
  **Parameters:**
464
-
465
216
  - `quad` (object) โ€” The quad to locate (subject, predicate, object)
466
- - `origin` (object, optional) โ€” Origin object containing blocks and quadIndex
467
- - `text` (string, optional) โ€” MDLD text (auto-parsed if origin not provided)
468
- - `context` (object, optional) โ€” Context for parsing when text needs to be parsed
217
+ - `origin` (object) โ€” Origin object containing quadIndex
469
218
 
470
- **Returns:** `{ blockId, entryIndex, range, content, blockRange, carrierType, isVacant }` or `null`
219
+ **Returns:** `{ blockId, range, carrierType, subject, predicate, context, value, polarity }` or `null`
471
220
 
472
- - `blockId` โ€” ID of the containing block
473
- - `entryIndex` โ€” Position within block entries
474
- - `range` โ€” Precise character range of the quad content
475
- - `content` โ€” Actual text content at that range
476
- - `blockRange` โ€” Full range of the containing block
477
- - `carrierType` โ€” Type of carrier (heading, blockquote, list, span)
478
- - `isVacant` โ€” Whether the slot is marked as vacant
221
+ ### `render(quads, options)`
479
222
 
480
- **Example:**
223
+ Render RDF quads as HTML+RDFa for web display.
481
224
 
482
- ```javascript
483
- import { parse, locate } from './src/index.js';
484
-
485
- const result = parse(mdldText, { context: { ex: 'http://example.org/' } });
486
- const quad = result.quads[0]; // Find a quad to locate
225
+ **Parameters:**
226
+ - `quads` (array) โ€” Array of RDF/JS Quads to render
227
+ - `options` (object, optional):
228
+ - `context` (object) โ€” Prefix mappings for CURIE shortening
229
+ - `baseIRI` (string) โ€” Base IRI for resolving relative references
487
230
 
488
- // Pattern 1: With origin (most efficient)
489
- const location1 = locate(quad, result.origin, mdldText);
231
+ **Returns:** `{ html, context }`
490
232
 
491
- // Pattern 2: Auto-parse text (convenient)
492
- const location2 = locate(quad, null, mdldText, { ex: 'http://example.org/' });
233
+ ### Utility Functions
493
234
 
494
- console.log(location1.range); // { start: 38, end: 44 }
495
- console.log(location1.content); // " Alice"
496
- console.log(location1.carrierType); // "blockquote"
235
+ ```javascript
236
+ import {
237
+ DEFAULT_CONTEXT, // Default prefix mappings
238
+ DataFactory, // RDF/JS DataFactory instance
239
+ hash, // String hashing function
240
+ expandIRI, // IRI expansion with context
241
+ shortenIRI, // IRI shortening with context
242
+ parseSemanticBlock // Parse semantic block syntax
243
+ } from 'mdld-parse';
497
244
  ```
498
245
 
499
- ## Value Carriers
500
-
501
- Only specific markdown elements can carry semantic values:
502
-
503
- **Inline:**
504
- - `[text] {...}` โ€” span with annotation
505
- - `[text](url) {...}` โ€” link to external resource
506
- - `[text] {...}` โ€” inline resource declaration
507
- - `![alt text](image.png) {...}` โ€” embedding with annotation
508
-
509
- **Block:**
510
- - Headings (`# Title`)
511
- - List items (`- item`, `1. item`) โ€” pure Markdown structure
512
- - Blockquotes (`> quote`)
513
- - Code blocks (` ```lang `)
514
-
515
- ## Architecture
246
+ ## ๐Ÿ—๏ธ Architecture
516
247
 
517
248
  ### Design Principles
518
-
519
249
  - **Zero dependencies** โ€” Pure JavaScript, ~15KB minified
520
250
  - **Streaming-first** โ€” Single-pass parsing, O(n) complexity
521
251
  - **Standards-compliant** โ€” RDF/JS data model
@@ -523,107 +253,13 @@ Only specific markdown elements can carry semantic values:
523
253
  - **Explicit semantics** โ€” No guessing, inference, or heuristics
524
254
 
525
255
  ### RDF/JS Compatibility
526
-
527
256
  Quads are compatible with:
528
-
529
257
  - [`n3.js`](https://github.com/rdfjs/N3.js) โ€” Turtle/N-Triples serialization
530
258
  - [`rdflib.js`](https://github.com/linkeddata/rdflib.js) โ€” RDF store and reasoning
531
259
  - [`sparqljs`](https://github.com/RubenVerborgh/SPARQL.js) โ€” SPARQL queries
532
260
  - [`rdf-ext`](https://github.com/rdf-ext/rdf-ext) โ€” Extended RDF utilities
533
261
 
534
- ## Forbidden Constructs
535
-
536
- MD-LD explicitly forbids to ensure deterministic parsing:
537
-
538
- - โŒ Implicit semantics or structural inference
539
- - โŒ Auto-generated subjects or blank nodes
540
- - โŒ Predicate guessing from context
541
- - โŒ Multi-pass or backtracking parsers
542
-
543
- Below is a **tight, README-ready refinement** of the Algebra section.
544
- It keeps the math precise, examples exhaustive, and language compact.
545
-
546
- ---
547
-
548
- ## Algebra
549
-
550
- > Every RDF triple `(s, p, o)` can be authored **explicitly, deterministically, and locally**, with no inference, guessing, or reordering.
551
-
552
- MD-LD models RDF authoring as a **closed edge algebra** over a small, explicit state. To be algebraically complete for RDF triple construction, a syntax must support:
553
-
554
- * Binding a **subject** `S`
555
- * Binding an **object** `O`
556
- * Emitting predicates in **both directions**
557
- * Distinguishing **IRI nodes** from **literal nodes**
558
- * Operating with **no implicit state or inference**
559
-
560
- MD-LD satisfies these requirements with four explicit operators.
561
-
562
- Each predicate is partitioned by **direction** and **node kind**:
563
-
564
- | Predicate form | Emitted triple |
565
- | -------------- | -------------- |
566
- | `p` | `S โ”€pโ†’ L` |
567
- | `?p` | `S โ”€pโ†’ O` |
568
- | not allowed | `L โ”€pโ†’ S` |
569
- | `!p` | `O โ”€pโ†’ S` |
570
-
571
- This spans all **2 ร— 2** combinations of:
572
-
573
- * source โˆˆ {subject, object/literal}
574
- * target โˆˆ {subject, object/literal}
575
-
576
- Therefore, the algebra is **closed**.
577
-
578
- ## Use Cases
579
-
580
- ### Personal Knowledge Management
581
-
582
- ```markdown
583
- [alice] <tag:alice@example.com,2026:>
584
-
585
- # Meeting Notes {=alice:meeting-2024-01-15 .alice:Meeting}
586
-
587
- Attendees:
588
-
589
- - **Alice** {+alice:alice ?alice:attendee label}
590
- - **Bob** {+alice:bob ?alice:attendee label}
591
-
592
- Action items:
593
-
594
- - **Review proposal** {+alice:task-1 ?alice:actionItem label}
595
- ```
596
-
597
- ### Developer Documentation
598
-
599
- ````markdown
600
- # API Endpoint {=api:/users/:id .api:Endpoint}
601
-
602
- [GET] {api:method}
603
- [/users/:id] {api:path}
604
-
605
- Example:
606
-
607
- ```bash {=api:/users/:id#example .api:CodeExample api:code}
608
- curl https://api.example.com/users/123
609
- ```
610
- ````
611
-
612
- ### Academic Research
613
-
614
- ```markdown
615
- [alice] <tag:alice@example.com,2026:>
616
-
617
- # Paper {=alice:paper-semantic-markdown .alice:ScholarlyArticle}
618
-
619
- [Semantic Web] {label}
620
- [Alice Johnson] {=alice:alice-johnson ?alice:author}
621
- [2024-01] {alice:datePublished ^^xsd:gYearMonth}
622
-
623
- > This paper explores semantic markup in Markdown. {comment @en}
624
- ```
625
-
626
- ## Testing
262
+ ## ๐Ÿงช Testing
627
263
 
628
264
  The parser includes comprehensive tests covering all spec requirements:
629
265
 
@@ -639,7 +275,7 @@ Tests validate:
639
275
  - Code blocks and blockquotes
640
276
  - Round-trip serialization
641
277
 
642
- ## Contributing
278
+ ## ๐Ÿค Contributing
643
279
 
644
280
  Contributions welcome! Please:
645
281
 
@@ -648,15 +284,6 @@ Contributions welcome! Please:
648
284
  3. Ensure all tests pass
649
285
  4. Follow existing code style
650
286
 
651
- ## Acknowledgments
652
-
653
- Developed by [Denis Starov](https://github.com/davay42).
654
-
655
- Inspired by:
656
- - Thomas Francart's [Semantic Markdown](https://blog.sparna.fr/2020/02/20/semantic-markdown/) article
657
- - RDFa decades of structured data experience
658
- - CommonMark's rigorous parsing approach
659
-
660
- ## License
287
+ ## ๐Ÿ“„ License
661
288
 
662
- See [LICENCE](./LICENCE)
289
+ See [LICENCE](./LICENCE)