mdld-parse 0.2.1 → 0.2.3

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.
Files changed (4) hide show
  1. package/LICENCE +167 -0
  2. package/README.md +352 -180
  3. package/index.js +290 -247
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -1,283 +1,455 @@
1
- # MD-LD Parse
1
+ # MD-LD Parse v0.2
2
2
 
3
- **Markdown-Linked Data (MD-LD)** — a human-friendly RDF authoring format that extends Markdown with semantic annotations.
3
+ **Markdown-Linked Data (MD-LD)** — a deterministic, streaming-friendly RDF authoring format that extends Markdown with explicit `{}` annotations.
4
4
 
5
- [NPM](https://www.npmjs.com/package/mdld-parse)
5
+ [![NPM](https://img.shields.io/npm/v/mdld-parse)](https://www.npmjs.com/package/mdld-parse)
6
+ [![License](https://img.shields.io/npm/l/mdld-parse)](https://github.com/mdld-js/mdld-parse)
6
7
 
7
- [Website](https://mdld.js.org)
8
+ [Documentation](https://mdld.js.org) | [Specification](https://mdld.js.org/spec) | [Playground](https://mdld.js.org/playground)
8
9
 
9
10
  ## What is MD-LD?
10
11
 
11
- MD-LD allows you to author RDF graphs directly in Markdown using familiar syntax:
12
+ MD-LD allows you to author RDF graphs directly in Markdown using explicit `{}` annotations:
12
13
 
13
14
  ```markdown
14
- # My Note {=urn:mdld:my-note-20251231 .NoteDigitalDocument}
15
+ # Apollo 11 {=ex:apollo11 .SpaceMission}
15
16
 
16
- [ex]{: http://example.org/}
17
+ Launch: [1969-07-16] {startDate ^^xsd:date}
18
+ Crew: [Neil Armstrong](ex:armstrong) {?crewMember}
19
+ Description: [First crewed Moon landing] {description}
20
+ ```
21
+
22
+ Generates valid RDF triples:
23
+
24
+ ```turtle
25
+ ex:apollo11 a schema:SpaceMission ;
26
+ schema:startDate "1969-07-16"^^xsd:date ;
27
+ schema:crewMember ex:armstrong ;
28
+ schema:description "First crewed Moon landing" .
29
+ ```
17
30
 
18
- Written by [Alice Johnson](=ex:alice){author .Person}
31
+ ## Core Guarantees
19
32
 
20
- ## Alice's biography {=ex:alice}
33
+ MD-LD v0.2 provides strict semantic guarantees:
21
34
 
22
- [Alice](ex:alice){name} works at [Tech Corp](=ex:tech-corp){worksFor .Organization}
35
+ 1. **CommonMark-preserving** Removing `{}` yields valid Markdown
36
+ 2. **Explicit semantics** — Every quad originates from explicit `{}`
37
+ 3. **Single-pass parsing** — Streaming-friendly, deterministic
38
+ 4. **No blank nodes** — All subjects are stable IRIs
39
+ 5. **Complete traceability** — Every quad maps to source location
40
+ 6. **Round-trip capable** — Markdown ↔ RDF ↔ Markdown preserves structure
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ npm install mdld-parse
23
46
  ```
24
47
 
25
- This generates valid RDF triples while remaining readable as plain Markdown.
48
+ ### Node.js
49
+
50
+ ```javascript
51
+ import { parse } from 'mdld-parse';
52
+
53
+ const markdown = `# Document {=ex:doc .Article}
54
+
55
+ [Alice] {author}`;
26
56
 
27
- ```n-quads
28
- <urn:mdld:my-note-20251231> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/NoteDigitalDocument> .
29
- <urn:mdld:my-note-20251231> <http://schema.org/author> <http://example.org/alice> .
30
- <http://example.org/alice> <http://schema.org/name> "Alice" .
31
- <http://example.org/alice> <http://schema.org/worksFor> <http://example.org/tech-corp> .
57
+ const result = parse(markdown, {
58
+ context: { ex: 'http://example.org/' }
59
+ });
60
+
61
+ console.log(result.quads);
62
+ // RDF/JS quads ready for n3.js, rdflib, etc.
32
63
  ```
33
64
 
34
- ## Architecture
65
+ ### Browser (ES Modules)
35
66
 
36
- ### Design Principles
67
+ ```html
68
+ <script type="module">
69
+ import { parse } from 'https://cdn.jsdelivr.net/npm/mdld-parse/+esm';
70
+
71
+ const result = parse('# Hello {=ex:hello}');
72
+ </script>
73
+ ```
37
74
 
38
- 1. **Streaming First** — Process documents incrementally without loading entire AST into memory
39
- 2. **Zero Dependencies** — Pure JavaScript, runs in Node.js and browsers
40
- 3. **Standards Compliant** — Outputs RDF quads compatible with RDFa semantics
41
- 4. **Markdown Native** — Plain Markdown yields minimal but valid RDF
42
- 5. **Progressive Enhancement** — Add semantics incrementally via attributes
43
- 6. **BaseIRI Inference** — Automatically infers baseIRI from document structure
44
- 7. **Default Vocabulary** — Provides default vocabulary for common properties, extensible via options
75
+ ## Semantic Model
45
76
 
46
- ### Stack Choices
77
+ MD-LD encodes a directed labeled multigraph where three nodes may be in scope:
47
78
 
48
- #### Parser: Custom Zero-Dependency Tokenizer
79
+ - **S** current subject (IRI)
80
+ - **O** — object resource (IRI from link/image)
81
+ - **L** — literal value (string + optional datatype/language)
49
82
 
50
- We implement a **minimal, purpose-built parser** for maximum control and zero dependencies:
83
+ ### Predicate Routing (§8.1)
51
84
 
52
- - **Custom Markdown tokenizer** Line-by-line parsing of headings, lists, paragraphs, code blocks
53
- - **Inline attribute parser** — Pandoc-style `{=iri .class key="value"}` attribute extraction
54
- - **RDF quad generator** — Direct mapping from tokens to RDF/JS quads
85
+ Each predicate form determines the graph edge:
55
86
 
56
- **Why custom?**
87
+ | Form | Edge | Example | Meaning |
88
+ |-------|---------|------------------------------|------------------|
89
+ | `p` | S → L | `[Alice] {name}` | literal property |
90
+ | `?p` | S → O | `[NASA](ex:nasa) {?org}` | object property |
91
+ | `^p` | *(none)*| *(literals can't be subjects)* | reverse literal |
92
+ | `^?p` | O → S | `[Parent](ex:p) {^?hasPart}` | reverse object |
57
93
 
58
- - **Zero dependencies** — Runs anywhere JavaScript runs
59
- - **Lightweight** — ~15KB minified, no AST overhead
60
- - **Focused** — Optimized specifically for MD-LD semantics
61
- - **Transparent** — Easy to understand and extend
62
- - **Fast** — Single-pass parsing with minimal allocations
94
+ ## Syntax Reference
63
95
 
64
- #### RDF Output: RDF/JS Data Model
96
+ ### Subject Declaration
65
97
 
66
- We implement the [RDF/JS specification](https://rdf.js.org/data-model-spec/):
98
+ Set the current subject (emits no quads):
67
99
 
68
- ```javascript
69
- {
70
- termType: 'NamedNode' | 'BlankNode' | 'Literal',
71
- value: string,
72
- language?: string,
73
- datatype?: NamedNode
74
- }
100
+ ```markdown
101
+ ## Apollo 11 {=ex:apollo11}
75
102
  ```
76
103
 
77
- This ensures compatibility with:
104
+ Subject remains in scope until reset with `{=}` or new subject declared.
78
105
 
79
- - `n3.js` — Turtle/N-Triples serialization
80
- - `rdflib.js` — RDF store and reasoning
81
- - `sparqljs` — SPARQL query parsing
82
- - `rdf-ext` — Extended RDF utilities
106
+ ### Type Declaration
83
107
 
84
- ### Processing Pipeline
108
+ Emit `rdf:type` triple:
85
109
 
110
+ ```markdown
111
+ ## Apollo 11 {=ex:apollo11 .SpaceMission .Event}
86
112
  ```
87
- Markdown Text
88
-
89
- [Custom Tokenizer] — Extract headings, lists, paragraphs, code blocks
90
-
91
- [Attribute Parser] — Parse {=iri .class key="value"} from tokens
92
-
93
- [Inline Parser] — Extract [text](url){attrs} spans
94
-
95
- [RDF Quad Generator] — Map tokens to RDF/JS quads
96
-
97
- RDF Quads (RDF/JS format)
98
-
99
- [Optional] n3.js Writer → Turtle/N-Triples
113
+
114
+ ```turtle
115
+ ex:apollo11 a schema:SpaceMission, schema:Event .
100
116
  ```
101
117
 
102
- ### Architecture Benefits
118
+ ### Literal Properties
103
119
 
104
- The zero-dependency design provides:
120
+ Inline value carriers emit literal properties:
105
121
 
106
- 1. **Single-pass parsing** — Process document once, emit quads immediately
107
- 2. **Minimal memory** — No AST construction, only token stream
108
- 3. **Predictable performance** — Linear time complexity, bounded memory
109
- 4. **Easy integration** — Works in Node.js, browsers, and edge runtimes
122
+ ```markdown
123
+ # Mission {=ex:apollo11}
110
124
 
111
- ## Installation
125
+ [Neil Armstrong] {commander}
126
+ [1969] {year ^^xsd:gYear}
127
+ [Historic mission] {description @en}
128
+ ```
112
129
 
113
- ### Node.js
130
+ ```turtle
131
+ ex:apollo11 schema:commander "Neil Armstrong" ;
132
+ schema:year "1969"^^xsd:gYear ;
133
+ schema:description "Historic mission"@en .
134
+ ```
114
135
 
115
- ```bash
116
- npm install mdld-parse
136
+ ### Object Properties
137
+
138
+ Links create relationships (use `?` prefix):
139
+
140
+ ```markdown
141
+ # Mission {=ex:apollo11}
142
+
143
+ [NASA](ex:nasa) {?organizer}
117
144
  ```
118
145
 
119
- ```javascript
120
- import { parse } from "mdld-parse";
146
+ ```turtle
147
+ ex:apollo11 schema:organizer ex:nasa .
148
+ ```
121
149
 
122
- const markdown = `# Hello {=urn:mdld:hello .Article}`;
123
- const result = parse(markdown);
124
- const quads = result.quads;
150
+ ### Resource Declaration
151
+
152
+ Declare resources inline with `(=iri)`:
153
+
154
+ ```markdown
155
+ # Mission {=ex:apollo11}
156
+
157
+ [Neil Armstrong](=ex:armstrong) {?commander .Person}
125
158
  ```
126
159
 
127
- ### Browser (via CDN)
160
+ ```turtle
161
+ ex:apollo11 schema:commander ex:armstrong .
162
+ ex:armstrong a schema:Person .
163
+ ```
128
164
 
129
- ```html
130
- <script type="importmap">
131
- {
132
- "imports": {
133
- "mdld-parse": "https://cdn.jsdelivr.net/npm/mdld-parse/+esm"
134
- }
135
- }
136
- </script>
165
+ ### Lists
137
166
 
138
- <script type="module">
139
- import { parse } from "mdld-parse";
140
- // use parse...
141
- </script>
167
+ Lists require explicit subjects per item:
168
+
169
+ ```markdown
170
+ # Recipe {=ex:recipe}
171
+
172
+ Ingredients: {?ingredient .Ingredient}
173
+
174
+ - [Flour](=ex:flour) {name}
175
+ - [Water](=ex:water) {name}
176
+ ```
177
+
178
+ ```turtle
179
+ ex:recipe schema:ingredient ex:flour, ex:water .
180
+ ex:flour a schema:Ingredient ; schema:name "Flour" .
181
+ ex:water a schema:Ingredient ; schema:name "Water" .
182
+ ```
183
+
184
+ ### Code Blocks
185
+
186
+ Code blocks are value carriers:
187
+
188
+ ````markdown
189
+ # Example {=ex:example}
190
+
191
+ ```javascript {=ex:code .SoftwareSourceCode text}
192
+ console.log("hello");
142
193
  ```
194
+ ````
143
195
 
144
- ## API
196
+ ```turtle
197
+ ex:code a schema:SoftwareSourceCode ;
198
+ schema:text "console.log(\"hello\")" .
199
+ ```
200
+
201
+ ### Blockquotes
202
+
203
+ ```markdown
204
+ # Article {=ex:article}
205
+
206
+ > MD-LD bridges Markdown and RDF. {abstract}
207
+ ```
208
+
209
+ ```turtle
210
+ ex:article schema:abstract "MD-LD bridges Markdown and RDF." .
211
+ ```
212
+
213
+ ### Reverse Relations
214
+
215
+ Reverse the relationship direction:
216
+
217
+ ```markdown
218
+ # Part {=ex:part}
219
+
220
+ Part of: {^?hasPart}
221
+
222
+ - [Book](=ex:book) {}
223
+ ```
224
+
225
+ ```turtle
226
+ ex:book schema:hasPart ex:part .
227
+ ```
228
+
229
+ ### Prefix Declarations
230
+
231
+ ```markdown
232
+ [ex] {: http://example.org/}
233
+ [foaf] {: http://xmlns.com/foaf/0.1/}
234
+
235
+ # Person {=ex:alice .foaf:Person}
236
+ ```
237
+
238
+ ## API Reference
145
239
 
146
240
  ### `parse(markdown, options)`
147
241
 
148
- Parse MD-LD markdown and return parsing result.
242
+ Parse MD-LD markdown and return RDF quads with origin tracking.
149
243
 
150
244
  **Parameters:**
151
245
 
152
246
  - `markdown` (string) — MD-LD formatted text
153
247
  - `options` (object, optional):
154
- - `baseIRI` (string) — Base IRI for relative references
155
- - `context` (object) — Additional context to merge with default context
156
- - `dataFactory` (object) — Custom RDF/JS DataFactory (default: built-in)
248
+ - `context` (object) — Prefix mappings (default: `{ '@vocab': 'http://schema.org/', rdf, rdfs, xsd, schema }`)
249
+ - `dataFactory` (object) — Custom RDF/JS DataFactory
250
+
251
+ **Returns:** `{ quads, origin, context }`
157
252
 
158
- **Returns:** Object containing:
159
253
  - `quads` — Array of RDF/JS Quads
160
- - `origin` — Object with `blocks` and `quadIndex` for serialization
161
- - `context` — Final context used for parsing
254
+ - `origin` — Origin tracking object with:
255
+ - `blocks` — Map of block IDs to source locations
256
+ - `quadIndex` — Map of quads to block IDs
257
+ - `context` — Final context used (includes prefixes)
258
+
259
+ **Example:**
260
+
261
+ ```javascript
262
+ const result = parse(
263
+ `# Article {=ex:article .Article}
264
+
265
+ [Alice](ex:alice) {?author}`,
266
+ { context: { ex: 'http://example.org/' } }
267
+ );
268
+
269
+ console.log(result.quads);
270
+ // [
271
+ // {
272
+ // subject: { termType: 'NamedNode', value: 'http://example.org/article' },
273
+ // predicate: { termType: 'NamedNode', value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' },
274
+ // object: { termType: 'NamedNode', value: 'http://schema.org/Article' }
275
+ // },
276
+ // ...
277
+ // ]
278
+ ```
162
279
 
163
280
  ### `serialize({ text, diff, origin, options })`
164
281
 
165
- Serialize RDF changes back to markdown with proper positioning.
282
+ Apply RDF changes back to markdown with proper positioning.
166
283
 
167
284
  **Parameters:**
168
285
 
169
- - `text` (string) — Original markdown text
286
+ - `text` (string) — Original markdown
170
287
  - `diff` (object) — Changes to apply:
171
- - `add` — Array of quads to add
172
- - `delete` — Array of quads to remove
173
- - `origin` (object) — Origin object from parse result
174
- - `options` (object, optional) — Additional options
288
+ - `add` (array) Quads to add
289
+ - `delete` (array) Quads to remove
290
+ - `origin` (object) — Origin from `parse()` result
291
+ - `options` (object, optional):
292
+ - `context` (object) — Context for IRI shortening
175
293
 
176
- **Returns:** Object containing:
177
- - `text` — Updated markdown text
178
- - `origin` — Updated origin object
294
+ **Returns:** `{ text, origin }`
179
295
 
180
- ```javascript
181
- const result = parse(
182
- `
183
- # Article Title {=ex:article .Article}
184
-
185
- Written by [Alice](ex:alice) {ex:author}
186
- `,
187
- {
188
- baseIRI: "http://example.org/doc",
189
- context: {
190
- '@vocab': 'http://schema.org/',
191
- },
192
- }
193
- );
296
+ - `text` — Updated markdown
297
+ - `origin` Updated origin tracking
298
+
299
+ **Example:**
194
300
 
195
- // result.quads[0] = {
196
- // subject: { termType: 'NamedNode', value: 'http://example.org/doc#article' },
197
- // predicate: { termType: 'NamedNode', value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' },
198
- // object: { termType: 'NamedNode', value: 'http://schema.org/Article' },
199
- // graph: { termType: 'DefaultGraph' }
200
- // }
301
+ ```javascript
302
+ const original = `# Article {=ex:article}
303
+
304
+ [Alice] {author}`;
305
+
306
+ const result = parse(original, { context: { ex: 'http://example.org/' } });
307
+
308
+ // Add a new property
309
+ const newQuad = {
310
+ subject: { termType: 'NamedNode', value: 'http://example.org/article' },
311
+ predicate: { termType: 'NamedNode', value: 'http://schema.org/datePublished' },
312
+ object: { termType: 'Literal', value: '2024-01-01' }
313
+ };
314
+
315
+ const updated = serialize({
316
+ text: original,
317
+ diff: { add: [newQuad] },
318
+ origin: result.origin,
319
+ options: { context: result.context }
320
+ });
321
+
322
+ console.log(updated.text);
323
+ // # Article {=ex:article}
324
+ //
325
+ // [Alice] {author}
326
+ // [2024-01-01] {datePublished}
201
327
  ```
202
328
 
203
- ## Implementation Details
329
+ ## Value Carriers
204
330
 
205
- ### Subject Resolution
331
+ Only specific markdown elements can carry semantic values:
206
332
 
207
- MD-LD follows a clear subject inheritance model:
333
+ **Inline:**
334
+ - `[text]` — span with annotation
335
+ - `[text](url)` — link to external resource
336
+ - `[text](=iri)` — inline resource declaration
208
337
 
209
- 1. **Root subject** — Declared in the first heading of the document or inferred it's text content
210
- 2. **Heading subjects** — `## Title {=ex:title .Type}`
211
- 3. **Inline subjects** `[text](=ex:text) {.Type}`
212
- 4. **Blank nodes** — Generated for incomplete triples
338
+ **Block:**
339
+ - Headings (`# Title`)
340
+ - List items (`- item`)
341
+ - Blockquotes (`> quote`)
342
+ - Code blocks (` ```lang `)
213
343
 
214
- ```markdown
215
- # Document {=urn:mdld:doc .Article}
344
+ **Non-carriers:**
345
+ - Plain paragraphs without `[...]`
346
+ - Images (future)
347
+ - Tables (future)
216
348
 
217
- ## Section 1 {=urn:mdld:sec1 .Section}
349
+ ## Architecture
218
350
 
219
- [Text] {name} ← property of sec1
351
+ ### Design Principles
220
352
 
221
- Back to [doc](=urn:mdld:doc) {hasPart}
222
- ```
353
+ - **Zero dependencies** — Pure JavaScript, ~15KB minified
354
+ - **Streaming-first** — Single-pass parsing, O(n) complexity
355
+ - **Standards-compliant** — RDF/JS data model
356
+ - **Origin tracking** — Full round-trip support with source maps
357
+ - **Explicit semantics** — No guessing, inference, or heuristics
223
358
 
224
- ### List Handling
359
+ ### RDF/JS Compatibility
225
360
 
226
- ```markdown {item}
227
- - Item 1
228
- - Item 2
229
- ```
361
+ Quads are compatible with:
230
362
 
231
- Creates **multiple triples** with same predicate (not RDF lists):
363
+ - [`n3.js`](https://github.com/rdfjs/N3.js) Turtle/N-Triples serialization
364
+ - [`rdflib.js`](https://github.com/linkeddata/rdflib.js) — RDF store and reasoning
365
+ - [`sparqljs`](https://github.com/RubenVerborgh/SPARQL.js) — SPARQL queries
366
+ - [`rdf-ext`](https://github.com/rdf-ext/rdf-ext) — Extended RDF utilities
232
367
 
233
- ```turtle
234
- <subject> schema:item "Item 1" .
235
- <subject> schema:item "Item 2" .
236
- ```
368
+ ## Forbidden Constructs
237
369
 
238
- ### Code Block Semantics
370
+ MD-LD explicitly forbids to ensure deterministic parsing:
239
371
 
240
- ```markdown
241
- \`\`\`sparql {=ex:query-1 .SoftwareSourceCode}
242
- SELECT \* WHERE { ?s ?p ?o }
243
- \`\`\`
244
- ```
372
+ - ❌ Implicit semantics or structural inference
373
+ - ❌ Auto-generated subjects or blank nodes
374
+ - Predicate guessing from context
375
+ - ❌ Multi-pass or backtracking parsers
245
376
 
246
- Creates:
377
+ ## Use Cases
247
378
 
248
- - A `schema:SoftwareSourceCode` resource (or custom type via `typeof`)
249
- - `schema:programmingLanguage` from the info string (`sparql`)
250
- - `schema:text` with the raw source code
251
- - `schema:hasPart` link from the surrounding section
379
+ ### Personal Knowledge Management
252
380
 
253
- This enables semantic queries like "find all SPARQL queries in my notes."
381
+ ```markdown
382
+ # Meeting Notes {=urn:note:2024-01-15 .Meeting}
254
383
 
255
- ## Syntax Overview
384
+ Attendees: {?attendee}
256
385
 
257
- ### Core Features
386
+ - [Alice](=urn:person:alice) {name}
387
+ - [Bob](=urn:person:bob) {name}
258
388
 
259
- **Subject Declaration** — Headings create typed subjects:
389
+ Action items: {?actionItem}
260
390
 
261
- ```markdown
262
- ## Alice Johnson {=ex:alice .Person}
391
+ - [Review proposal](=urn:task:1) {name}
263
392
  ```
264
393
 
265
- **Literal Properties** — Inline spans create properties:
394
+ ### Developer Documentation
266
395
 
267
- ```markdown
268
- [Alice Johnson] {name}
269
- [30] {age ^^xsd:integer}
396
+ ````markdown
397
+ # API Endpoint {=api:/users/:id .APIEndpoint}
398
+
399
+ [GET] {method}
400
+ [/users/:id] {path}
401
+
402
+ Example:
403
+
404
+ ```bash {=api:/users/:id/example .CodeExample programmingLanguage}
405
+ curl https://api.example.com/users/123
270
406
  ```
407
+ ````
271
408
 
272
- **Object Properties** — Links create relationships:
409
+ ### Academic Research
273
410
 
274
411
  ```markdown
275
- [Tech Corp](=ex:company) {worksFor}
412
+ # Paper {=doi:10.1234/example .ScholarlyArticle}
413
+
414
+ [Semantic Web] {about}
415
+ [Alice Johnson](=orcid:0000-0001-2345-6789) {?author .Person}
416
+ [2024-01] {datePublished ^^xsd:gYearMonth}
417
+
418
+ > This paper explores semantic markup in Markdown. {abstract @en}
276
419
  ```
277
420
 
278
- **Lists** — Repeated properties:
421
+ ## Testing
279
422
 
280
- ```markdown {tag}
281
- - Item 1
282
- - Item 2
423
+ The parser includes comprehensive tests covering all spec requirements:
424
+
425
+ ```bash
426
+ npm test
283
427
  ```
428
+
429
+ Tests validate:
430
+ - Subject declaration and context
431
+ - All predicate forms (p, ?p, ^p, ^?p)
432
+ - Datatypes and language tags
433
+ - List processing
434
+ - Code blocks and blockquotes
435
+ - Round-trip serialization
436
+
437
+ ## Contributing
438
+
439
+ Contributions welcome! Please:
440
+
441
+ 1. Read the [specification](https://mdld.js.org/spec)
442
+ 2. Add tests for new features
443
+ 3. Ensure all tests pass
444
+ 4. Follow existing code style
445
+
446
+ ## Acknowledgments
447
+
448
+ Inspired by:
449
+ - Thomas Francart's [Semantic Markdown](https://blog.sparna.fr/2020/02/20/semantic-markdown/)
450
+ - RDFa decades of structured data experience
451
+ - CommonMark's rigorous parsing approach
452
+
453
+ ## License
454
+
455
+ See [LICENCE](./LICENCE)