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 +100 -473
- package/package.json +1 -1
- package/src/generate.js +5 -89
- package/src/index.js +1 -1
- package/src/locate.js +21 -58
- package/src/merge.js +131 -0
- package/src/parse.js +72 -25
- package/src/utils.js +37 -120
- package/src/applyDiff.js +0 -583
package/README.md
CHANGED
|
@@ -4,87 +4,86 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/mdld-parse)
|
|
6
6
|
|
|
7
|
-
[
|
|
7
|
+
[Demo](https://mdld.js.org) | [Repository](https://github.com/davay42/mdld-parse)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## ๐ Quick Start
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
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
|
-
|
|
15
|
+
```javascript
|
|
16
|
+
import { parse } from 'mdld-parse';
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
const result = parse(`
|
|
19
|
+
[ex] <http://example.org/>
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
# Document {=ex:doc .ex:Article label}
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
[Alice] {?ex:author =ex:alice .prov:Person ex:firstName label}
|
|
24
|
+
[Smith] {ex:lastName}`);
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
+
## โจ Core Features
|
|
63
49
|
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
|
|
62
|
+
MD-LD allows you to author RDF graphs directly in Markdown using explicit `{...}` annotations:
|
|
76
63
|
|
|
77
|
-
```
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
- `
|
|
340
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) โ
|
|
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
|
-
**
|
|
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
|
|
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
|
-
**
|
|
209
|
+
**Returns:** `{ text, context }`
|
|
434
210
|
|
|
435
|
-
|
|
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
|
|
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
|
|
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,
|
|
219
|
+
**Returns:** `{ blockId, range, carrierType, subject, predicate, context, value, polarity }` or `null`
|
|
471
220
|
|
|
472
|
-
|
|
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
|
-
|
|
223
|
+
Render RDF quads as HTML+RDFa for web display.
|
|
481
224
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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
|
-
|
|
489
|
-
const location1 = locate(quad, result.origin, mdldText);
|
|
231
|
+
**Returns:** `{ html, context }`
|
|
490
232
|
|
|
491
|
-
|
|
492
|
-
const location2 = locate(quad, null, mdldText, { ex: 'http://example.org/' });
|
|
233
|
+
### Utility Functions
|
|
493
234
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
-
##
|
|
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
|
-
- ` {...}` โ 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
|
-
##
|
|
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
|
-
##
|
|
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)
|