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.
- package/package.json +1 -1
- 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.
|
|
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: (
|
|
12
|
-
blankNode: (
|
|
13
|
-
literal: (
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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) {
|