mdld-parse 0.6.2 โ 0.7.1
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 +119 -473
- package/package.json +1 -4
- 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 +134 -24
- package/src/utils.js +37 -120
- package/src/applyDiff.js +0 -583
package/README.md
CHANGED
|
@@ -4,87 +4,87 @@
|
|
|
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
|
|
59
|
+
- **๐ฏ Elevated statements** - Automatic rdf:Statement pattern detection for "golden" graph extraction
|
|
65
60
|
|
|
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
|
|
61
|
+
## ๐ What is MD-LD?
|
|
74
62
|
|
|
75
|
-
|
|
63
|
+
MD-LD allows you to author RDF graphs directly in Markdown using explicit `{...}` annotations:
|
|
76
64
|
|
|
77
|
-
```
|
|
78
|
-
|
|
65
|
+
```markdown
|
|
66
|
+
[my] <tag:alice@example.com,2026:>
|
|
67
|
+
# 2024-07-18 {=my:journal-2024-07-18 .my:Event my:date ^^xsd:date}
|
|
68
|
+
## A good day {label}
|
|
69
|
+
Mood: [Happy] {my:mood}
|
|
70
|
+
Energy level: [8] {my:energyLevel ^^xsd:integer}
|
|
71
|
+
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
72
|
```
|
|
80
73
|
|
|
74
|
+
Generates valid RDF triples with complete provenance tracking.
|
|
75
|
+
|
|
76
|
+
## ๐ฆ Installation
|
|
77
|
+
|
|
81
78
|
### Node.js
|
|
82
79
|
|
|
80
|
+
```bash
|
|
81
|
+
pnpm install mdld-parse
|
|
82
|
+
```
|
|
83
|
+
|
|
83
84
|
```javascript
|
|
84
85
|
import { parse } from 'mdld-parse';
|
|
85
86
|
|
|
86
87
|
const markdown = `# Document {=ex:doc .Article}
|
|
87
|
-
|
|
88
88
|
[Alice] {author}`;
|
|
89
89
|
|
|
90
90
|
const result = parse(markdown, {
|
|
@@ -101,11 +101,11 @@ console.log(result.quads);
|
|
|
101
101
|
<script type="module">
|
|
102
102
|
import { parse } from 'https://cdn.jsdelivr.net/npm/mdld-parse/+esm';
|
|
103
103
|
|
|
104
|
-
const result = parse('# Hello {=ex:hello}');
|
|
104
|
+
const result = parse('# Hello {=ex:hello label}');
|
|
105
105
|
</script>
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
## Semantic Model
|
|
108
|
+
## ๐ง Semantic Model
|
|
109
109
|
|
|
110
110
|
MD-LD encodes a directed labeled multigraph where three nodes may be in scope:
|
|
111
111
|
|
|
@@ -123,399 +123,148 @@ Each predicate form determines the graph edge:
|
|
|
123
123
|
| `?p` | S โ O | `[NASA] {=ex:nasa ?org}` | object property |
|
|
124
124
|
| `!p` | O โ S | `[Parent] {=ex:p !hasPart}` | reverse object |
|
|
125
125
|
|
|
126
|
-
##
|
|
126
|
+
## ๏ฟฝ Elevated Statements
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
MD-LD automatically detects `rdf:Statement` patterns during parsing and extracts elevated SPO quads for convenient consumption by applications.
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
### Pattern Detection
|
|
131
|
+
|
|
132
|
+
When the parser encounters a complete `rdf:Statement` pattern with `rdf:subject`, `rdf:predicate`, and `rdf:object`, it automatically adds the corresponding SPO quad to the `statements` array:
|
|
131
133
|
|
|
134
|
+
```markdown
|
|
135
|
+
[ex] <http://example.org/>
|
|
136
|
+
|
|
137
|
+
## Elevated statement {=ex:stmt1 .rdf:Statement}
|
|
138
|
+
**Alice** {+ex:alice ?rdf:subject} *knows* {+ex:knows ?rdf:predicate} **Bob** {+ex:bob ?rdf:object}
|
|
139
|
+
|
|
140
|
+
Direct statement:**Alice** {=ex:alice} knows **Bob** {?ex:knows +ex:bob}
|
|
141
|
+
``
|
|
142
|
+
|
|
143
|
+
## ๏ฟฝ๐จ Syntax Quick Reference
|
|
144
|
+
|
|
145
|
+
### Subject Declaration
|
|
146
|
+
Set current subject (emits no quads):
|
|
132
147
|
```markdown
|
|
133
148
|
## Apollo 11 {=ex:apollo11}
|
|
134
149
|
```
|
|
135
150
|
|
|
136
|
-
|
|
137
|
-
|
|
151
|
+
### Fragment Syntax
|
|
138
152
|
Create fragment IRIs relative to current subject:
|
|
139
|
-
|
|
140
153
|
```markdown
|
|
141
154
|
# Document {=ex:document}
|
|
142
155
|
{=#summary}
|
|
143
156
|
[Content] {label}
|
|
144
157
|
```
|
|
145
|
-
|
|
146
|
-
```turtle
|
|
147
|
-
ex:document#summary rdfs:label "Content" .
|
|
148
|
-
```
|
|
149
|
-
|
|
150
158
|
Fragments replace any existing fragment and require a current subject.
|
|
151
159
|
|
|
152
|
-
Subject remains in scope until reset with `{=}` or new subject declared.
|
|
153
|
-
|
|
154
160
|
### Type Declaration
|
|
155
|
-
|
|
156
161
|
Emit `rdf:type` triple:
|
|
157
|
-
|
|
158
162
|
```markdown
|
|
159
163
|
## Apollo 11 {=ex:apollo11 .ex:SpaceMission .ex:Event}
|
|
160
164
|
```
|
|
161
165
|
|
|
162
|
-
```turtle
|
|
163
|
-
ex:apollo11 a ex:SpaceMission, ex:Event .
|
|
164
|
-
```
|
|
165
|
-
|
|
166
166
|
### Literal Properties
|
|
167
|
-
|
|
168
167
|
Inline value carriers emit literal properties:
|
|
169
|
-
|
|
170
168
|
```markdown
|
|
171
169
|
# Mission {=ex:apollo11}
|
|
172
|
-
|
|
173
170
|
[Neil Armstrong] {ex:commander}
|
|
174
171
|
[1969] {ex:year ^^xsd:gYear}
|
|
175
172
|
[Historic mission] {ex:description @en}
|
|
176
173
|
```
|
|
177
174
|
|
|
178
|
-
```turtle
|
|
179
|
-
ex:apollo11 ex:commander "Neil Armstrong" ;
|
|
180
|
-
ex:year "1969"^^xsd:gYear ;
|
|
181
|
-
ex:description "Historic mission"@en .
|
|
182
|
-
```
|
|
183
|
-
|
|
184
175
|
### Object Properties
|
|
185
|
-
|
|
186
176
|
Links create relationships (use `?` prefix):
|
|
187
|
-
|
|
188
177
|
```markdown
|
|
189
178
|
# Mission {=ex:apollo11}
|
|
190
|
-
|
|
191
179
|
[NASA] {=ex:nasa ?ex:organizer}
|
|
192
180
|
```
|
|
193
181
|
|
|
194
|
-
```turtle
|
|
195
|
-
ex:apollo11 ex:organizer ex:nasa .
|
|
196
|
-
```
|
|
197
|
-
|
|
198
182
|
### Resource Declaration
|
|
199
|
-
|
|
200
183
|
Declare resources inline with `{=iri}`:
|
|
201
|
-
|
|
202
184
|
```markdown
|
|
203
185
|
# Mission {=ex:apollo11}
|
|
204
|
-
|
|
205
186
|
[Neil Armstrong] {=ex:armstrong ?ex:commander .prov:Person}
|
|
206
187
|
```
|
|
207
188
|
|
|
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
|
|
189
|
+
## ๐ง API Reference
|
|
324
190
|
|
|
325
191
|
### `parse(markdown, options)`
|
|
326
192
|
|
|
327
|
-
Parse MD-LD markdown and return RDF quads with origin tracking.
|
|
193
|
+
Parse MD-LD markdown and return RDF quads with lean origin tracking.
|
|
328
194
|
|
|
329
195
|
**Parameters:**
|
|
330
|
-
|
|
331
196
|
- `markdown` (string) โ MD-LD formatted text
|
|
332
197
|
- `options` (object, optional):
|
|
333
198
|
- `context` (object) โ Prefix mappings (default: `{ '@vocab': 'http://www.w3.org/2000/01/rdf-schema#', rdf, rdfs, xsd, sh, prov }`)
|
|
334
199
|
- `dataFactory` (object) โ Custom RDF/JS DataFactory
|
|
335
200
|
|
|
336
|
-
**Returns:** `{ quads, origin, context }`
|
|
201
|
+
**Returns:** `{ quads, remove, statements, origin, context }`
|
|
337
202
|
|
|
338
|
-
- `quads` โ Array of RDF/JS Quads
|
|
339
|
-
- `
|
|
340
|
-
|
|
341
|
-
|
|
203
|
+
- `quads` โ Array of RDF/JS Quads (final resolved graph state)
|
|
204
|
+
- `remove` โ Array of RDF/JS Quads (external retractions targeting prior state)
|
|
205
|
+
- `statements` โ Array of elevated RDF/JS Quads extracted from rdf:Statement patterns
|
|
206
|
+
- `origin` โ Lean origin tracking object with quadIndex for UI navigation
|
|
342
207
|
- `context` โ Final context used (includes prefixes)
|
|
343
208
|
|
|
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 })`
|
|
209
|
+
### `merge(docs, options)`
|
|
366
210
|
|
|
367
|
-
|
|
211
|
+
Merge multiple MDLD documents with diff polarity resolution.
|
|
368
212
|
|
|
369
213
|
**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
|
|
214
|
+
- `docs` (array) โ Array of markdown strings or ParseResult objects
|
|
376
215
|
- `options` (object, optional):
|
|
377
|
-
- `context` (object) โ
|
|
378
|
-
|
|
379
|
-
**Returns:** `{ text, origin }`
|
|
380
|
-
|
|
381
|
-
- `text` โ Updated markdown
|
|
382
|
-
- `origin` โ Updated origin tracking vacant slots
|
|
383
|
-
|
|
384
|
-
**Example:**
|
|
385
|
-
|
|
386
|
-
```javascript
|
|
387
|
-
const original = `# Article {=ex:article}
|
|
216
|
+
- `context` (object) โ Prefix mappings (merged with DEFAULT_CONTEXT)
|
|
388
217
|
|
|
389
|
-
|
|
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
|
-
```
|
|
218
|
+
**Returns:** `{ quads, remove, origin, context }`
|
|
413
219
|
|
|
414
220
|
### `generate(quads, context)`
|
|
415
221
|
|
|
416
|
-
Generate deterministic MDLD from RDF quads
|
|
222
|
+
Generate deterministic MDLD from RDF quads.
|
|
417
223
|
|
|
418
224
|
**Parameters:**
|
|
419
|
-
|
|
420
225
|
- `quads` (array) โ Array of RDF/JS Quads to convert
|
|
421
226
|
- `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
|
-
|
|
433
|
-
**Example:**
|
|
434
|
-
|
|
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
227
|
|
|
453
|
-
|
|
454
|
-
// # Article {=ex:article .ex:Article}
|
|
455
|
-
//
|
|
456
|
-
// > alice {+ex:alice ?ex:author}
|
|
457
|
-
```
|
|
228
|
+
**Returns:** `{ text, context }`
|
|
458
229
|
|
|
459
|
-
### `locate(quad, origin
|
|
230
|
+
### `locate(quad, origin)`
|
|
460
231
|
|
|
461
|
-
Locate the
|
|
232
|
+
Locate the origin entry for a quad using the lean origin system.
|
|
462
233
|
|
|
463
234
|
**Parameters:**
|
|
464
|
-
|
|
465
235
|
- `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
|
|
236
|
+
- `origin` (object) โ Origin object containing quadIndex
|
|
469
237
|
|
|
470
|
-
**Returns:** `{ blockId,
|
|
238
|
+
**Returns:** `{ blockId, range, carrierType, subject, predicate, context, value, polarity }` or `null`
|
|
471
239
|
|
|
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
|
|
240
|
+
### `render(quads, options)`
|
|
479
241
|
|
|
480
|
-
|
|
242
|
+
Render RDF quads as HTML+RDFa for web display.
|
|
481
243
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
244
|
+
**Parameters:**
|
|
245
|
+
- `quads` (array) โ Array of RDF/JS Quads to render
|
|
246
|
+
- `options` (object, optional):
|
|
247
|
+
- `context` (object) โ Prefix mappings for CURIE shortening
|
|
248
|
+
- `baseIRI` (string) โ Base IRI for resolving relative references
|
|
487
249
|
|
|
488
|
-
|
|
489
|
-
const location1 = locate(quad, result.origin, mdldText);
|
|
250
|
+
**Returns:** `{ html, context }`
|
|
490
251
|
|
|
491
|
-
|
|
492
|
-
const location2 = locate(quad, null, mdldText, { ex: 'http://example.org/' });
|
|
252
|
+
### Utility Functions
|
|
493
253
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
254
|
+
```javascript
|
|
255
|
+
import {
|
|
256
|
+
DEFAULT_CONTEXT, // Default prefix mappings
|
|
257
|
+
DataFactory, // RDF/JS DataFactory instance
|
|
258
|
+
hash, // String hashing function
|
|
259
|
+
expandIRI, // IRI expansion with context
|
|
260
|
+
shortenIRI, // IRI shortening with context
|
|
261
|
+
parseSemanticBlock // Parse semantic block syntax
|
|
262
|
+
} from 'mdld-parse';
|
|
497
263
|
```
|
|
498
264
|
|
|
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
|
|
265
|
+
## ๐๏ธ Architecture
|
|
516
266
|
|
|
517
267
|
### Design Principles
|
|
518
|
-
|
|
519
268
|
- **Zero dependencies** โ Pure JavaScript, ~15KB minified
|
|
520
269
|
- **Streaming-first** โ Single-pass parsing, O(n) complexity
|
|
521
270
|
- **Standards-compliant** โ RDF/JS data model
|
|
@@ -523,107 +272,13 @@ Only specific markdown elements can carry semantic values:
|
|
|
523
272
|
- **Explicit semantics** โ No guessing, inference, or heuristics
|
|
524
273
|
|
|
525
274
|
### RDF/JS Compatibility
|
|
526
|
-
|
|
527
275
|
Quads are compatible with:
|
|
528
|
-
|
|
529
276
|
- [`n3.js`](https://github.com/rdfjs/N3.js) โ Turtle/N-Triples serialization
|
|
530
277
|
- [`rdflib.js`](https://github.com/linkeddata/rdflib.js) โ RDF store and reasoning
|
|
531
278
|
- [`sparqljs`](https://github.com/RubenVerborgh/SPARQL.js) โ SPARQL queries
|
|
532
279
|
- [`rdf-ext`](https://github.com/rdf-ext/rdf-ext) โ Extended RDF utilities
|
|
533
280
|
|
|
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
|
|
281
|
+
## ๐งช Testing
|
|
627
282
|
|
|
628
283
|
The parser includes comprehensive tests covering all spec requirements:
|
|
629
284
|
|
|
@@ -639,7 +294,7 @@ Tests validate:
|
|
|
639
294
|
- Code blocks and blockquotes
|
|
640
295
|
- Round-trip serialization
|
|
641
296
|
|
|
642
|
-
## Contributing
|
|
297
|
+
## ๐ค Contributing
|
|
643
298
|
|
|
644
299
|
Contributions welcome! Please:
|
|
645
300
|
|
|
@@ -648,15 +303,6 @@ Contributions welcome! Please:
|
|
|
648
303
|
3. Ensure all tests pass
|
|
649
304
|
4. Follow existing code style
|
|
650
305
|
|
|
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
|
|
306
|
+
## ๐ License
|
|
661
307
|
|
|
662
|
-
See [LICENCE](./LICENCE)
|
|
308
|
+
See [LICENCE](./LICENCE)
|