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.
Files changed (4) hide show
  1. package/LICENCE +1 -1
  2. package/README.md +10 -10
  3. package/index.js +24 -18
  4. package/package.json +1 -1
package/LICENCE CHANGED
@@ -1,6 +1,6 @@
1
1
  # MDLD / MD-LD Community License
2
2
 
3
- Version 0.2 — 2025
3
+ Version 0.3 — 2025
4
4
 
5
5
  Copyright © 2025–present
6
6
  **Denis Starov**
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # MD-LD Parse v0.2
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] {=?ex:armstrong ?crewMember fullName}
17
+ Crew: [Neil Armstrong] {+ex:armstrong ?crewMember name}
18
18
  Description: [First crewed Moon landing] {description}
19
19
 
20
- [Section] {=?#overview ?hasPart}
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:fullName "Neil Armstrong" .
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**: `{=?IRI}` and `{=?#fragment}` for temporary object declarations
39
- - **Four predicate forms**: `p` (S→L), `?p` (S→O), `^p` (L→S), `^?p` (O→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
- | `^?p` | O → S | `[Parent](ex:p) {^?hasPart}` | reverse object |
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: {^?hasPart}
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
- | `^?p` | `O ─p→ S` |
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, ^?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(3);
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(2);
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(2);
123
- result.predicates.push({ iri, form: '^?', entryIndex });
124
- result.entries.push({ kind: 'property', iri, form: '^?', relRange: { start: relStart, end: relEnd }, raw: token });
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
- if (pred.form === '^' || pred.form === '^?') {
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 = `=?${iri}`;
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 = `=?${iri}`;
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 = `=?#${fragment}`;
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 = `=?#${fragment}`;
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}] {=?${objectShort} ?${predShort}}` });
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}] {=?#${fragment} ?${predShort}}` });
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}] {=?${objectShort} ?${predShort}}` });
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.2.9",
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",