mdld-parse 0.7.5 → 0.7.7
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 +11 -16
- package/package.json +1 -1
- package/src/generate.js +13 -7
- package/src/merge.js +8 -1
- package/src/parse.js +8 -1
- package/LICENCE +0 -167
package/README.md
CHANGED
|
@@ -198,13 +198,14 @@ Parse MD-LD markdown and return RDF quads with lean origin tracking.
|
|
|
198
198
|
- `context` (object) — Prefix mappings (default: `{ '@vocab': 'http://www.w3.org/2000/01/rdf-schema#', rdf, rdfs, xsd, sh, prov }`)
|
|
199
199
|
- `dataFactory` (object) — Custom RDF/JS DataFactory
|
|
200
200
|
|
|
201
|
-
**Returns:** `{ quads, remove, statements, origin, context }`
|
|
201
|
+
**Returns:** `{ quads, remove, statements, origin, context, primarySubject }`
|
|
202
202
|
|
|
203
203
|
- `quads` — Array of RDF/JS Quads (final resolved graph state)
|
|
204
204
|
- `remove` — Array of RDF/JS Quads (external retractions targeting prior state)
|
|
205
205
|
- `statements` — Array of elevated RDF/JS Quads extracted from rdf:Statement patterns
|
|
206
206
|
- `origin` — Lean origin tracking object with quadIndex for UI navigation
|
|
207
207
|
- `context` — Final context used (includes prefixes)
|
|
208
|
+
- `primarySubject` — String IRI or null (first non-fragment subject declaration)
|
|
208
209
|
|
|
209
210
|
### `merge(docs, options)`
|
|
210
211
|
|
|
@@ -215,15 +216,22 @@ Merge multiple MDLD documents with diff polarity resolution.
|
|
|
215
216
|
- `options` (object, optional):
|
|
216
217
|
- `context` (object) — Prefix mappings (merged with DEFAULT_CONTEXT)
|
|
217
218
|
|
|
218
|
-
**Returns:** `{ quads, remove, origin, context }`
|
|
219
|
+
**Returns:** `{ quads, remove, origin, context, primarySubjects }`
|
|
219
220
|
|
|
220
|
-
|
|
221
|
+
- `quads` — Array of RDF/JS Quads (final resolved graph state)
|
|
222
|
+
- `remove` — Array of RDF/JS Quads (external retractions targeting prior state)
|
|
223
|
+
- `origin` — Merge origin tracking with document index and polarity
|
|
224
|
+
- `context` — Final merged context
|
|
225
|
+
- `primarySubjects` — Array of string IRIs (primary subjects from each document, in merge order)
|
|
226
|
+
|
|
227
|
+
### `generate(quads, context, primarySubject)`
|
|
221
228
|
|
|
222
229
|
Generate deterministic MDLD from RDF quads.
|
|
223
230
|
|
|
224
231
|
**Parameters:**
|
|
225
232
|
- `quads` (array) — Array of RDF/JS Quads to convert
|
|
226
233
|
- `context` (object, optional) — Prefix mappings (default: `{}`)
|
|
234
|
+
- `primarySubject` (string, optional) — String IRI to place first in output (ensures round-trip safety)
|
|
227
235
|
|
|
228
236
|
**Returns:** `{ text, context }`
|
|
229
237
|
|
|
@@ -293,16 +301,3 @@ Tests validate:
|
|
|
293
301
|
- Explicit list item annotations
|
|
294
302
|
- Code blocks and blockquotes
|
|
295
303
|
- Round-trip serialization
|
|
296
|
-
|
|
297
|
-
## 🤝 Contributing
|
|
298
|
-
|
|
299
|
-
Contributions welcome! Please:
|
|
300
|
-
|
|
301
|
-
1. Read the [specification](https://mdld.js.org/spec)
|
|
302
|
-
2. Add tests for new features
|
|
303
|
-
3. Ensure all tests pass
|
|
304
|
-
4. Follow existing code style
|
|
305
|
-
|
|
306
|
-
## 📄 License
|
|
307
|
-
|
|
308
|
-
See [LICENCE](./LICENCE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdld-parse",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
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",
|
package/src/generate.js
CHANGED
|
@@ -34,17 +34,17 @@ export function extractLocalName(iri, ctx = {}) {
|
|
|
34
34
|
/**
|
|
35
35
|
* Generate deterministic MDLD from RDF quads
|
|
36
36
|
* Purpose: TTL→MDLD conversion with canonical structure
|
|
37
|
-
* Input: RDF quads + context
|
|
37
|
+
* Input: RDF quads + context + optional primarySubject (string IRI)
|
|
38
38
|
* Output: MDLD text
|
|
39
39
|
*/
|
|
40
|
-
export function generate(quads, context = {}) {
|
|
40
|
+
export function generate(quads, context = {}, primarySubject = null) {
|
|
41
41
|
const fullContext = { ...DEFAULT_CONTEXT, ...context };
|
|
42
42
|
|
|
43
43
|
const normalizedQuads = normalizeAndSortQuads(quads);
|
|
44
44
|
|
|
45
45
|
const subjectGroups = groupQuadsBySubject(normalizedQuads);
|
|
46
46
|
|
|
47
|
-
const { text } = buildDeterministicMDLD(subjectGroups, fullContext);
|
|
47
|
+
const { text } = buildDeterministicMDLD(subjectGroups, fullContext, primarySubject);
|
|
48
48
|
|
|
49
49
|
return text;
|
|
50
50
|
}
|
|
@@ -86,7 +86,7 @@ function groupQuadsBySubject(quads) {
|
|
|
86
86
|
return groups;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
function buildDeterministicMDLD(subjectGroups, context) {
|
|
89
|
+
function buildDeterministicMDLD(subjectGroups, context, primarySubject = null) {
|
|
90
90
|
let text = '';
|
|
91
91
|
const usedPrefixes = collectUsedPrefixes(subjectGroups, context);
|
|
92
92
|
|
|
@@ -103,10 +103,16 @@ function buildDeterministicMDLD(subjectGroups, context) {
|
|
|
103
103
|
text += '\n';
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// Process subjects in deterministic order
|
|
106
|
+
// Process subjects in deterministic order, with primary subject first
|
|
107
107
|
const sortedSubjects = Array.from(subjectGroups.keys()).sort();
|
|
108
|
+
const primarySubjectIRI = primarySubject; // Already a string IRI
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
// If primary subject exists, place it first
|
|
111
|
+
const orderedSubjects = primarySubjectIRI
|
|
112
|
+
? [primarySubjectIRI, ...sortedSubjects.filter(s => s !== primarySubjectIRI)]
|
|
113
|
+
: sortedSubjects;
|
|
114
|
+
|
|
115
|
+
for (const subjectIRI of orderedSubjects) {
|
|
110
116
|
const subjectQuads = subjectGroups.get(subjectIRI);
|
|
111
117
|
const shortSubject = shortenIRI(subjectIRI, context);
|
|
112
118
|
|
|
@@ -119,7 +125,7 @@ function buildDeterministicMDLD(subjectGroups, context) {
|
|
|
119
125
|
? ' ' + types.map(t => '.' + shortenIRI(t.object.value, context)).sort().join(' ')
|
|
120
126
|
: '';
|
|
121
127
|
|
|
122
|
-
text += `# ${localSubjectName} {=${shortSubject}${typeAnnotations}}\n`;
|
|
128
|
+
text += `# ${localSubjectName} {=${shortSubject}${typeAnnotations}}\n\n`;
|
|
123
129
|
|
|
124
130
|
// Add literals and objects using shared utilities
|
|
125
131
|
sortQuadsByPredicate(literals).forEach(quad => {
|
package/src/merge.js
CHANGED
|
@@ -42,6 +42,7 @@ export function merge(docs, options = {}) {
|
|
|
42
42
|
const quadIndex = new Map();
|
|
43
43
|
const allStatements = []; // Collect statements from all documents
|
|
44
44
|
const accumulatedContext = new Map(); // Track all unique prefixes across documents
|
|
45
|
+
const primarySubjects = []; // Collect primary subjects from all documents
|
|
45
46
|
|
|
46
47
|
// Process each document in order
|
|
47
48
|
for (let i = 0; i < docs.length; i++) {
|
|
@@ -78,6 +79,11 @@ export function merge(docs, options = {}) {
|
|
|
78
79
|
allStatements.push(...doc.statements);
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
// Collect primary subject from this document (already a string IRI)
|
|
83
|
+
if (doc.primarySubject) {
|
|
84
|
+
primarySubjects.push(doc.primarySubject);
|
|
85
|
+
}
|
|
86
|
+
|
|
81
87
|
// Fold assertions into session buffer
|
|
82
88
|
for (const quad of doc.quads) {
|
|
83
89
|
const key = quadKey(quad);
|
|
@@ -144,6 +150,7 @@ export function merge(docs, options = {}) {
|
|
|
144
150
|
remove: filteredRemove,
|
|
145
151
|
statements: allStatements, // Include all collected statements
|
|
146
152
|
origin: mergeOrigin,
|
|
147
|
-
context: finalContext
|
|
153
|
+
context: finalContext,
|
|
154
|
+
primarySubjects: primarySubjects // Include all collected primary subjects
|
|
148
155
|
};
|
|
149
156
|
}
|
package/src/parse.js
CHANGED
|
@@ -49,6 +49,7 @@ export function parse(text, options = {}) {
|
|
|
49
49
|
const state = {
|
|
50
50
|
ctx: { ...DEFAULT_CONTEXT, ...(options.context || {}) },
|
|
51
51
|
df: options.dataFactory || DataFactory,
|
|
52
|
+
graph: DataFactory.namedNode(options.graph) || DataFactory.defaultGraph(),
|
|
52
53
|
quads: [],
|
|
53
54
|
quadBuffer: new Map(),
|
|
54
55
|
removeSet: new Set(),
|
|
@@ -58,6 +59,7 @@ export function parse(text, options = {}) {
|
|
|
58
59
|
documentStructure: []
|
|
59
60
|
},
|
|
60
61
|
currentSubject: null,
|
|
62
|
+
primarySubject: null,
|
|
61
63
|
tokens: null,
|
|
62
64
|
currentTokenIndex: -1,
|
|
63
65
|
statements: [],
|
|
@@ -107,7 +109,7 @@ export function parse(text, options = {}) {
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
return { quads: state.quads, remove: filteredRemove, statements: state.statements, origin: state.origin, context: state.ctx };
|
|
112
|
+
return { quads: state.quads, remove: filteredRemove, statements: state.statements, origin: state.origin, context: state.ctx, primarySubject: state.primarySubject };
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
|
|
@@ -387,6 +389,11 @@ function processAnnotationWithBlockTracking(carrier, sem, state, options = {}) {
|
|
|
387
389
|
const newSubject = resolveSubject(sem, state);
|
|
388
390
|
const localObject = resolveObject(sem, state);
|
|
389
391
|
|
|
392
|
+
// Track primary subject: first non-fragment subject declaration (fixed once detected)
|
|
393
|
+
if (newSubject && !state.primarySubject && !sem.subject.startsWith('=#')) {
|
|
394
|
+
state.primarySubject = newSubject.value; // Store as string IRI
|
|
395
|
+
}
|
|
396
|
+
|
|
390
397
|
const effectiveSubject = implicitSubject || (newSubject && !preserveGlobalSubject ? newSubject : previousSubject);
|
|
391
398
|
if (newSubject && !preserveGlobalSubject && !implicitSubject) {
|
|
392
399
|
state.currentSubject = newSubject;
|
package/LICENCE
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
# MDLD / MD-LD Community License
|
|
2
|
-
|
|
3
|
-
Version 0.3 — 2025
|
|
4
|
-
|
|
5
|
-
Copyright © 2025–present
|
|
6
|
-
**Denis Starov**
|
|
7
|
-
All rights reserved.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 0. Definitions
|
|
12
|
-
|
|
13
|
-
For the purposes of this license:
|
|
14
|
-
|
|
15
|
-
**“MDLD” or “MD-LD”** refers to the Markdown-Linked Data specification, including all versions, drafts, documentation, reference implementations, tests, examples, and associated materials published by the author.
|
|
16
|
-
|
|
17
|
-
**“Commercial Use”** means any use of MDLD that is part of, or directly supports, a for-profit activity, including but not limited to the offering of products or services for sale, subscription, advertising, data monetization, or other commercial advantage.
|
|
18
|
-
|
|
19
|
-
**“Server-side use”** means processing, storing, transforming, or serving MDLD documents on infrastructure operated by a third party for multiple users, including hosted platforms and network-accessible services.
|
|
20
|
-
|
|
21
|
-
**“For-profit entity”** means any organization or legal entity operating with profit intent, including corporations, subsidiaries, startups, and entities backed by private equity or venture capital, regardless of current revenue.
|
|
22
|
-
|
|
23
|
-
**“Proprietary AI system”** means any artificial intelligence or machine learning system whose model weights, training data, or full source code are not publicly available under an OSI-approved open-source license.
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## 1. Scope
|
|
28
|
-
|
|
29
|
-
This license applies to:
|
|
30
|
-
|
|
31
|
-
- The MDLD / MD-LD specification
|
|
32
|
-
- All reference implementations
|
|
33
|
-
- Documentation, examples, test suites, and published materials
|
|
34
|
-
- Associated repositories and official distributions
|
|
35
|
-
|
|
36
|
-
This license does not grant rights to independently created works that merely interoperate with MDLD, provided they do not copy or derive from the licensed materials.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## 2. Guiding intent (non-normative)
|
|
41
|
-
|
|
42
|
-
MDLD is designed to support individuals, educators, researchers, and communities in creating, exchanging, and working with structured knowledge in an open and durable way.
|
|
43
|
-
|
|
44
|
-
This license seeks to encourage broad personal and community use while preventing unacknowledged commercial appropriation, standard capture, and extraction of value into proprietary platforms, particularly in the context of hosted services and large-scale AI systems.
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## 3. Permitted use (no permission required)
|
|
49
|
-
|
|
50
|
-
The following uses are permitted worldwide and royalty-free:
|
|
51
|
-
|
|
52
|
-
### 3.1 Individual and community use
|
|
53
|
-
|
|
54
|
-
- Authoring, reading, and sharing MDLD documents
|
|
55
|
-
- Personal, local, or offline tools and workflows
|
|
56
|
-
- Open-source software released under OSI-approved licenses
|
|
57
|
-
- Non-commercial websites, static content, and community projects
|
|
58
|
-
- Internal use by individuals for personal productivity
|
|
59
|
-
|
|
60
|
-
### 3.2 Research and education
|
|
61
|
-
|
|
62
|
-
- Academic research conducted by non-profit institutions
|
|
63
|
-
- Teaching, learning, and scholarly experimentation
|
|
64
|
-
- Non-commercial prototypes, demonstrations, and publications
|
|
65
|
-
|
|
66
|
-
### 3.3 Personal AI and local automation
|
|
67
|
-
|
|
68
|
-
- Use of MDLD with local or third-party AI tools for personal, educational, or research purposes
|
|
69
|
-
- Interactive or single-user analysis of MDLD documents
|
|
70
|
-
- Automation workflows that do not provide MDLD processing as a hosted service to others
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## 4. Restricted use (explicit permission required)
|
|
75
|
-
|
|
76
|
-
The following uses are not permitted without explicit written permission from the author:
|
|
77
|
-
|
|
78
|
-
### 4.1 Commercial server-side services
|
|
79
|
-
|
|
80
|
-
- Offering MDLD processing, storage, or transformation as part of a hosted, multi-user, or server-side service
|
|
81
|
-
- Software-as-a-Service (SaaS), cloud platforms, or subscription products where MDLD is a core or marketed feature
|
|
82
|
-
- Paid APIs or hosted tools that accept or emit MDLD documents
|
|
83
|
-
|
|
84
|
-
### 4.2 Artificial intelligence and machine learning systems
|
|
85
|
-
|
|
86
|
-
- Training, fine-tuning, or evaluating proprietary or closed-source AI or ML models using:
|
|
87
|
-
- the MDLD specification
|
|
88
|
-
- reference implementations
|
|
89
|
-
- example corpora, tests, or documentation
|
|
90
|
-
- Including MDLD materials in commercial datasets, benchmarks, or evaluation suites
|
|
91
|
-
- Providing paid AI features or services that rely on MDLD as an input or output format
|
|
92
|
-
|
|
93
|
-
### 4.3 For-profit product and platform use
|
|
94
|
-
|
|
95
|
-
- Use of MDLD by for-profit entities as part of any product, platform, or service offering made available to customers, users, or clients
|
|
96
|
-
- Use that contributes to the development, protection, or monetization of proprietary technology, products, or services
|
|
97
|
-
- Use that is reasonably expected to support commercial differentiation, intellectual property claims, or capital formation
|
|
98
|
-
|
|
99
|
-
### 4.4 Standard capture and misrepresentation
|
|
100
|
-
|
|
101
|
-
- Representing MDLD as an independently governed or competing standard without permission
|
|
102
|
-
- Claiming authorship, stewardship, or official status with respect to MDLD
|
|
103
|
-
- Publishing incompatible extensions, variants, or forks under the MDLD or MD-LD name
|
|
104
|
-
|
|
105
|
-
### 4.5 Internal corporate use
|
|
106
|
-
|
|
107
|
-
Internal use of MDLD by for-profit entities is permitted solely for temporary evaluation or experimentation.
|
|
108
|
-
|
|
109
|
-
Continued internal use that supports, informs, or precedes a commercial product or service requires explicit permission.
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## 5. Attribution and naming
|
|
114
|
-
|
|
115
|
-
Any permitted use must include clear attribution:
|
|
116
|
-
|
|
117
|
-
> “MDLD / MD-LD — Markdown-Linked Data, by Denis Starov”
|
|
118
|
-
|
|
119
|
-
The names “MDLD” and “MD-LD” may not be used to identify derivative formats, forks, or extensions without explicit permission.
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## 6. No trademark grant
|
|
124
|
-
|
|
125
|
-
This license does not grant any trademark rights.
|
|
126
|
-
|
|
127
|
-
All trademarks, service marks, and names associated with MDLD remain the property of the author.
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 7. Commercial licensing
|
|
132
|
-
|
|
133
|
-
Commercial use is possible under a separate written agreement.
|
|
134
|
-
|
|
135
|
-
Commercial licenses may include rights for:
|
|
136
|
-
|
|
137
|
-
- SaaS and hosted services
|
|
138
|
-
- AI and machine learning systems
|
|
139
|
-
- Enterprise redistribution
|
|
140
|
-
- Long-term support or collaboration
|
|
141
|
-
|
|
142
|
-
Contact details for commercial licensing are provided in the official repository.
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## 8. Termination
|
|
147
|
-
|
|
148
|
-
Any use in violation of this license automatically terminates all rights granted herein.
|
|
149
|
-
|
|
150
|
-
Upon termination, the violating party must immediately cease all use, distribution, and promotion of the MDLD materials.
|
|
151
|
-
|
|
152
|
-
Termination does not require notice and does not limit the author’s right to pursue other remedies.
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## 9. No warranty
|
|
157
|
-
|
|
158
|
-
MDLD and all associated materials are provided “as is”, without warranty of any kind, express or implied.
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## 10. License versions
|
|
163
|
-
|
|
164
|
-
This license applies on a per-version basis.
|
|
165
|
-
|
|
166
|
-
Future versions of this license do not retroactively alter rights granted under this version.
|
|
167
|
-
Users may elect to adopt newer versions at their discretion.
|