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 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
- ### `generate(quads, context)`
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.5",
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
- for (const subjectIRI of sortedSubjects) {
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.