mdld-parse 0.2.9 → 0.3.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/LICENCE +1 -1
- package/README.md +10 -10
- package/index.js +24 -18
- package/package.json +1 -1
package/LICENCE
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# MD-LD Parse v0.
|
|
1
|
+
# MD-LD Parse v0.3
|
|
2
2
|
|
|
3
3
|
**Markdown-Linked Data (MD-LD)** — a deterministic, streaming-friendly RDF authoring format that extends Markdown with explicit `{...}` annotations.
|
|
4
4
|
|
|
@@ -14,10 +14,10 @@ MD-LD allows you to author RDF graphs directly in Markdown using explicit `{...}
|
|
|
14
14
|
# Apollo 11 {=ex:apollo11 .SpaceMission}
|
|
15
15
|
|
|
16
16
|
Launch: [1969-07-16] {startDate ^^xsd:date}
|
|
17
|
-
Crew: [Neil Armstrong] {
|
|
17
|
+
Crew: [Neil Armstrong] {+ex:armstrong ?crewMember name}
|
|
18
18
|
Description: [First crewed Moon landing] {description}
|
|
19
19
|
|
|
20
|
-
[Section] {
|
|
20
|
+
[Section] {+#overview ?hasPart}
|
|
21
21
|
Overview: [Mission summary] {description}
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -29,14 +29,14 @@ ex:apollo11 a schema:SpaceMission ;
|
|
|
29
29
|
schema:crewMember ex:armstrong ;
|
|
30
30
|
schema:description "First crewed Moon landing" .
|
|
31
31
|
|
|
32
|
-
ex:armstrong schema:
|
|
32
|
+
ex:armstrong schema:name "Neil Armstrong" .
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
## Core Features
|
|
36
36
|
|
|
37
37
|
- **Subject declarations**: `{=IRI}` and `{=#fragment}` for context setting
|
|
38
|
-
- **Object IRIs**: `{
|
|
39
|
-
- **Four predicate forms**: `p` (S→L), `?p` (S→O), `^p` (L→S),
|
|
38
|
+
- **Object IRIs**: `{+IRI}` and `{+#fragment}` for temporary object declarations
|
|
39
|
+
- **Four predicate forms**: `p` (S→L), `?p` (S→O), `^p` (L→S), `!p` (O→S)
|
|
40
40
|
- **Type declarations**: `.Class` for rdf:type triples
|
|
41
41
|
- **Datatypes & language**: `^^xsd:date` and `@en` support
|
|
42
42
|
- **Lists**: Explicit subject declarations for structured data
|
|
@@ -93,7 +93,7 @@ Each predicate form determines the graph edge:
|
|
|
93
93
|
| `p` | S → L | `[Alice] {name}` | literal property |
|
|
94
94
|
| `?p` | S → O | `[NASA](ex:nasa) {?org}` | object property |
|
|
95
95
|
| `^p` | *(none)*| *(literals can't be subjects)* | reverse literal |
|
|
96
|
-
|
|
|
96
|
+
| `!p` | O → S | `[Parent](ex:p) {!hasPart}` | reverse object |
|
|
97
97
|
|
|
98
98
|
## Syntax Reference
|
|
99
99
|
|
|
@@ -237,7 +237,7 @@ Reverse the relationship direction:
|
|
|
237
237
|
```markdown
|
|
238
238
|
# Part {=ex:part}
|
|
239
239
|
|
|
240
|
-
Part of: {
|
|
240
|
+
Part of: {!hasPart}
|
|
241
241
|
|
|
242
242
|
- Book {=ex:book}
|
|
243
243
|
```
|
|
@@ -417,7 +417,7 @@ Each predicate is partitioned by **direction** and **node kind**:
|
|
|
417
417
|
| `p` | `S ─p→ L` |
|
|
418
418
|
| `?p` | `S ─p→ O` |
|
|
419
419
|
| `^p` | `L ─p→ S` |
|
|
420
|
-
|
|
|
420
|
+
| `!p` | `O ─p→ S` |
|
|
421
421
|
|
|
422
422
|
This spans all **2 × 2** combinations of:
|
|
423
423
|
|
|
@@ -480,7 +480,7 @@ npm test
|
|
|
480
480
|
|
|
481
481
|
Tests validate:
|
|
482
482
|
- Subject declaration and context
|
|
483
|
-
- All predicate forms (p, ?p, ^p,
|
|
483
|
+
- All predicate forms (p, ?p, ^p, !p)
|
|
484
484
|
- Datatypes and language tags
|
|
485
485
|
- List processing
|
|
486
486
|
- Code blocks and blockquotes
|
package/index.js
CHANGED
|
@@ -75,15 +75,15 @@ export function parseSemanticBlock(raw) {
|
|
|
75
75
|
continue;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
if (token.startsWith('
|
|
79
|
-
const fragment = token.substring(
|
|
78
|
+
if (token.startsWith('+#')) {
|
|
79
|
+
const fragment = token.substring(2);
|
|
80
80
|
result.object = `#${fragment}`;
|
|
81
81
|
result.entries.push({ kind: 'softFragment', fragment, relRange: { start: relStart, end: relEnd }, raw: token });
|
|
82
82
|
continue;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
if (token.startsWith('
|
|
86
|
-
const iri = token.substring(
|
|
85
|
+
if (token.startsWith('+')) {
|
|
86
|
+
const iri = token.substring(1);
|
|
87
87
|
result.object = iri;
|
|
88
88
|
result.entries.push({ kind: 'object', iri, relRange: { start: relStart, end: relEnd }, raw: token });
|
|
89
89
|
continue;
|
|
@@ -118,10 +118,10 @@ export function parseSemanticBlock(raw) {
|
|
|
118
118
|
continue;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
if (token.startsWith('
|
|
122
|
-
const iri = token.substring(
|
|
123
|
-
result.predicates.push({ iri, form: '
|
|
124
|
-
result.entries.push({ kind: 'property', iri, form: '
|
|
121
|
+
if (token.startsWith('!')) {
|
|
122
|
+
const iri = token.substring(1);
|
|
123
|
+
result.predicates.push({ iri, form: '!', entryIndex });
|
|
124
|
+
result.entries.push({ kind: 'property', iri, form: '!', relRange: { start: relStart, end: relEnd }, raw: token });
|
|
125
125
|
continue;
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -593,7 +593,7 @@ function processAnnotation(carrier, sem, state) {
|
|
|
593
593
|
// L —p→ S (use soft IRI object as subject if available, otherwise current subject)
|
|
594
594
|
const subjectIRI = localObject || S;
|
|
595
595
|
emitQuad(state.quads, state.origin.quadIndex, block.id, L, P, subjectIRI, state.df, { kind: 'pred', token, form: pred.form, expandedPredicate: P.value, entryIndex: pred.entryIndex });
|
|
596
|
-
} else if (pred.form === '
|
|
596
|
+
} else if (pred.form === '!') {
|
|
597
597
|
// O —p→ S (use previous subject as object, newSubject as subject)
|
|
598
598
|
const objectIRI = newSubject ? previousSubject : S;
|
|
599
599
|
const subjectIRI = localObject || newSubject || carrierO;
|
|
@@ -660,11 +660,17 @@ function processListContext(contextSem, listTokens, state, contextSubject = null
|
|
|
660
660
|
|
|
661
661
|
contextSem.predicates.forEach(pred => {
|
|
662
662
|
const P = state.df.namedNode(expandIRI(pred.iri, state.ctx));
|
|
663
|
-
|
|
663
|
+
|
|
664
|
+
// According to MD-LD spec: list predicates that connect to item subjects MUST use object predicate forms (?p or !p)
|
|
665
|
+
// Literal predicate forms (p, ^p) in list scope emit no quads
|
|
666
|
+
if (pred.form === '!') {
|
|
667
|
+
// Reverse object property: O —p→ S
|
|
664
668
|
emitQuad(state.quads, state.origin.quadIndex, 'list-context', itemSubject, P, contextSubject, state.df);
|
|
665
|
-
} else {
|
|
669
|
+
} else if (pred.form === '?') {
|
|
670
|
+
// Object property: S —p→ O
|
|
666
671
|
emitQuad(state.quads, state.origin.quadIndex, 'list-context', contextSubject, P, itemSubject, state.df);
|
|
667
672
|
}
|
|
673
|
+
// Note: pred.form === '' and pred.form === '^' are intentionally ignored (literal predicate forms)
|
|
668
674
|
});
|
|
669
675
|
|
|
670
676
|
const prevSubject = state.currentSubject;
|
|
@@ -791,22 +797,22 @@ function removeOneToken(tokens, matchFn) {
|
|
|
791
797
|
}
|
|
792
798
|
|
|
793
799
|
function addObjectToken(tokens, iri) {
|
|
794
|
-
const objectToken =
|
|
800
|
+
const objectToken = `+${iri}`;
|
|
795
801
|
return tokens.includes(objectToken) ? tokens : [...tokens, objectToken];
|
|
796
802
|
}
|
|
797
803
|
|
|
798
804
|
function removeObjectToken(tokens, iri) {
|
|
799
|
-
const objectToken =
|
|
805
|
+
const objectToken = `+${iri}`;
|
|
800
806
|
return removeOneToken(tokens, t => t === objectToken);
|
|
801
807
|
}
|
|
802
808
|
|
|
803
809
|
function addSoftFragmentToken(tokens, fragment) {
|
|
804
|
-
const fragmentToken =
|
|
810
|
+
const fragmentToken = `+#${fragment}`;
|
|
805
811
|
return tokens.includes(fragmentToken) ? tokens : [...tokens, fragmentToken];
|
|
806
812
|
}
|
|
807
813
|
|
|
808
814
|
function removeSoftFragmentToken(tokens, fragment) {
|
|
809
|
-
const fragmentToken =
|
|
815
|
+
const fragmentToken = `+#${fragment}`;
|
|
810
816
|
return removeOneToken(tokens, t => t === fragmentToken);
|
|
811
817
|
}
|
|
812
818
|
|
|
@@ -1197,7 +1203,7 @@ export function serialize({ text, diff, origin, options = {} }) {
|
|
|
1197
1203
|
const full = quad.object.value;
|
|
1198
1204
|
const label = shortenIRI(full, ctx);
|
|
1199
1205
|
const objectShort = shortenIRI(full, ctx);
|
|
1200
|
-
edits.push({ start: result.length, end: result.length, text: `\n[${label}] {
|
|
1206
|
+
edits.push({ start: result.length, end: result.length, text: `\n[${label}] {+${objectShort} ?${predShort}}` });
|
|
1201
1207
|
}
|
|
1202
1208
|
return;
|
|
1203
1209
|
}
|
|
@@ -1240,9 +1246,9 @@ export function serialize({ text, diff, origin, options = {} }) {
|
|
|
1240
1246
|
// Create new annotation with object token
|
|
1241
1247
|
if (isSoftFragment) {
|
|
1242
1248
|
const fragment = full.split('#')[1];
|
|
1243
|
-
edits.push({ start: result.length, end: result.length, text: `\n[${objectShort}] {
|
|
1249
|
+
edits.push({ start: result.length, end: result.length, text: `\n[${objectShort}] {+#${fragment} ?${predShort}}` });
|
|
1244
1250
|
} else {
|
|
1245
|
-
edits.push({ start: result.length, end: result.length, text: `\n[${objectShort}] {
|
|
1251
|
+
edits.push({ start: result.length, end: result.length, text: `\n[${objectShort}] {+${objectShort} ?${predShort}}` });
|
|
1246
1252
|
}
|
|
1247
1253
|
}
|
|
1248
1254
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdld-parse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A standards-compliant parser for **MD-LD (Markdown-Linked Data)** — a human-friendly RDF authoring format that extends Markdown with semantic annotations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|