mdld-parse 0.5.5 → 0.5.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/utils.js +217 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdld-parse",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
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/utils.js CHANGED
@@ -7,16 +7,226 @@ export const DEFAULT_CONTEXT = {
7
7
  prov: 'http://www.w3.org/ns/prov#'
8
8
  };
9
9
 
10
+ // Base Term class for RDF/JS compatibility
11
+ export class Term {
12
+ constructor(id) {
13
+ this.id = id;
14
+ }
15
+
16
+ equals(other) {
17
+ return !!other && this.termType === other.termType && this.value === other.value;
18
+ }
19
+ }
20
+
21
+ // NamedNode implementation
22
+ export class NamedNode extends Term {
23
+ constructor(iri) {
24
+ super(iri);
25
+ this.termType = 'NamedNode';
26
+ this.value = iri;
27
+ }
28
+ }
29
+
30
+ // Literal implementation with language/direction support
31
+ export class Literal extends Term {
32
+ constructor(id) {
33
+ super(id);
34
+ this.termType = 'Literal';
35
+ this.value = '';
36
+ this.language = '';
37
+ this.datatype = null;
38
+
39
+ // Parse the literal ID - handle escaped quotes properly
40
+ const dtMatch = id.match(/^"([^"\\]*(?:\\.[^"\\]*)*)"(\^\^([^"]+))?(@([^-]+)(--(.+))?)?$/);
41
+ if (dtMatch) {
42
+ // Unescape the value
43
+ this.value = dtMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
44
+ if (dtMatch[5]) {
45
+ this.language = dtMatch[5];
46
+ this.datatype = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString');
47
+ } else if (dtMatch[3]) {
48
+ this.datatype = new NamedNode(dtMatch[3]);
49
+ } else {
50
+ this.datatype = new NamedNode('http://www.w3.org/2001/XMLSchema#string');
51
+ }
52
+ } else {
53
+ // Fallback for simple literals without complex parsing
54
+ this.value = id.replace(/^"|"$/g, '');
55
+ this.datatype = new NamedNode('http://www.w3.org/2001/XMLSchema#string');
56
+ }
57
+ }
58
+
59
+ equals(other) {
60
+ return !!other &&
61
+ this.termType === other.termType &&
62
+ this.value === other.value &&
63
+ this.language === other.language &&
64
+ this.datatype?.value === other.datatype?.value;
65
+ }
66
+ }
67
+
68
+ // BlankNode implementation
69
+ export class BlankNode extends Term {
70
+ constructor(name) {
71
+ super(name || `b${Math.random().toString(36).slice(2, 11)}`);
72
+ this.termType = 'BlankNode';
73
+ this.value = this.id;
74
+ }
75
+ }
76
+
77
+ // Variable implementation
78
+ export class Variable extends Term {
79
+ constructor(name) {
80
+ super(name);
81
+ this.termType = 'Variable';
82
+ this.value = name;
83
+ }
84
+ }
85
+
86
+ // DefaultGraph implementation
87
+ export class DefaultGraph extends Term {
88
+ constructor() {
89
+ super('');
90
+ this.termType = 'DefaultGraph';
91
+ this.value = '';
92
+ }
93
+
94
+ equals(other) {
95
+ return !!other && this.termType === other.termType;
96
+ }
97
+ }
98
+
99
+ // Default graph singleton
100
+ const DEFAULTGRAPH = new DefaultGraph();
101
+
102
+ // Quad implementation
103
+ export class Quad extends Term {
104
+ constructor(subject, predicate, object, graph = DEFAULTGRAPH) {
105
+ super(`${subject.id}|${predicate.id}|${object.id}|${graph.id}`);
106
+ this.termType = 'Quad';
107
+ this.subject = subject;
108
+ this.predicate = predicate;
109
+ this.object = object;
110
+ this.graph = graph;
111
+ }
112
+
113
+ equals(other) {
114
+ return !!other &&
115
+ this.termType === other.termType &&
116
+ this.subject.equals(other.subject) &&
117
+ this.predicate.equals(other.predicate) &&
118
+ this.object.equals(other.object) &&
119
+ this.graph.equals(other.graph);
120
+ }
121
+
122
+ toJSON() {
123
+ return {
124
+ termType: this.termType,
125
+ subject: this.subject.toJSON ? this.subject.toJSON() : { termType: this.subject.termType, value: this.subject.value },
126
+ predicate: this.predicate.toJSON ? this.predicate.toJSON() : { termType: this.predicate.termType, value: this.predicate.value },
127
+ object: this.object.toJSON ? this.object.toJSON() : { termType: this.object.termType, value: this.object.value },
128
+ graph: this.graph.toJSON ? this.graph.toJSON() : { termType: this.graph.termType, value: this.graph.value }
129
+ };
130
+ }
131
+ }
132
+
133
+ // XSD constants
134
+ const xsd = {
135
+ boolean: 'http://www.w3.org/2001/XMLSchema#boolean',
136
+ integer: 'http://www.w3.org/2001/XMLSchema#integer',
137
+ double: 'http://www.w3.org/2001/XMLSchema#double',
138
+ string: 'http://www.w3.org/2001/XMLSchema#string'
139
+ };
140
+
141
+ // DataFactory singleton matching N3.js interface
10
142
  export const DataFactory = {
11
- namedNode: (v) => ({ termType: 'NamedNode', value: v }),
12
- blankNode: (v = `b${Math.random().toString(36).slice(2, 11)}`) => ({ termType: 'BlankNode', value: v }),
13
- literal: (v, lang) => {
14
- if (typeof lang === 'string') {
15
- return { termType: 'Literal', value: v, language: lang, datatype: DataFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString') };
143
+ namedNode: (iri) => new NamedNode(iri),
144
+ blankNode: (name) => new BlankNode(name),
145
+ literal: (value, languageOrDataType) => {
146
+ // Convert non-string values to string for proper serialization
147
+ const stringValue = String(value);
148
+ // Escape quotes in the value for proper serialization
149
+ const escapedValue = stringValue.replace(/"/g, '\\"');
150
+
151
+ // Create a language-tagged string
152
+ if (typeof languageOrDataType === 'string') {
153
+ return new Literal(`"${escapedValue}"@${languageOrDataType.toLowerCase()}`);
154
+ }
155
+
156
+ // Create a language-tagged string with base direction
157
+ if (languageOrDataType !== undefined && !('termType' in languageOrDataType)) {
158
+ const direction = languageOrDataType.direction ? `--${languageOrDataType.direction.toLowerCase()}` : '';
159
+ return new Literal(`"${escapedValue}"@${languageOrDataType.language.toLowerCase()}${direction}`);
160
+ }
161
+
162
+ // Automatically determine datatype for booleans and numbers
163
+ let datatype = languageOrDataType ? languageOrDataType.value : '';
164
+ if (datatype === '') {
165
+ // Convert a boolean
166
+ if (typeof value === 'boolean') {
167
+ datatype = xsd.boolean;
168
+ }
169
+ // Convert an integer or double
170
+ else if (typeof value === 'number') {
171
+ if (Number.isFinite(value)) {
172
+ datatype = Number.isInteger(value) ? xsd.integer : xsd.double;
173
+ } else {
174
+ datatype = xsd.double;
175
+ if (!Number.isNaN(value)) {
176
+ value = value > 0 ? 'INF' : '-INF';
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ // Create a datatyped literal
183
+ return (datatype === '' || datatype === xsd.string)
184
+ ? new Literal(`"${escapedValue}"`)
185
+ : new Literal(`"${escapedValue}"^^${datatype}`);
186
+ },
187
+ variable: (name) => new Variable(name),
188
+ defaultGraph: () => DEFAULTGRAPH,
189
+ quad: (subject, predicate, object, graph) => new Quad(subject, predicate, object, graph),
190
+ triple: (subject, predicate, object, graph) => new Quad(subject, predicate, object, graph), // Alias for quad
191
+ fromTerm: (term) => {
192
+ if (term instanceof Term) return term;
193
+
194
+ // Term instantiated with another library
195
+ switch (term.termType) {
196
+ case 'NamedNode':
197
+ return new NamedNode(term.value);
198
+ case 'BlankNode':
199
+ return new BlankNode(term.value);
200
+ case 'Variable':
201
+ return new Variable(term.value);
202
+ case 'DefaultGraph':
203
+ return DEFAULTGRAPH;
204
+ case 'Literal':
205
+ if (term.language) {
206
+ return new Literal(`"${term.value}"@${term.language}`);
207
+ } else if (term.datatype) {
208
+ return new Literal(`"${term.value}"^^${term.datatype.value || term.datatype}`);
209
+ } else {
210
+ return new Literal(`"${term.value}"`);
211
+ }
212
+ case 'Quad':
213
+ return DataFactory.fromQuad(term);
214
+ default:
215
+ throw new Error(`Unexpected termType: ${term.termType}`);
16
216
  }
17
- return { termType: 'Literal', value: v, language: '', datatype: lang || DataFactory.namedNode('http://www.w3.org/2001/XMLSchema#string') };
18
217
  },
19
- quad: (s, p, o, g) => ({ subject: s, predicate: p, object: o, graph: g || DataFactory.namedNode('') })
218
+ fromQuad: (inQuad) => {
219
+ if (inQuad instanceof Quad) return inQuad;
220
+ if (inQuad.termType !== 'Quad') {
221
+ throw new Error(`Unexpected termType: ${inQuad.termType}`);
222
+ }
223
+ return new Quad(
224
+ DataFactory.fromTerm(inQuad.subject),
225
+ DataFactory.fromTerm(inQuad.predicate),
226
+ DataFactory.fromTerm(inQuad.object),
227
+ DataFactory.fromTerm(inQuad.graph)
228
+ );
229
+ }
20
230
  };
21
231
 
22
232
  export function hash(str) {