n3.js-messages 0.1.4 → 0.2.1
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 +109 -7
- package/browser/THIRD-PARTY-LICENSES.txt +172 -0
- package/browser/index.global.js +27 -0
- package/browser/index.global.js.LEGAL.txt +15 -0
- package/browser/index.global.js.map +7 -0
- package/browser/index.js +27 -0
- package/browser/index.js.LEGAL.txt +15 -0
- package/browser/index.js.map +7 -0
- package/browser.d.ts +26 -0
- package/common.d.ts +91 -0
- package/index.d.ts +2 -86
- package/lib/MessageParser.js +38 -4
- package/lib/MessageParser.js.map +1 -0
- package/lib/MessageParserCore.js +51 -12
- package/lib/MessageParserCore.js.map +1 -0
- package/lib/MessageStreamParser.js +12 -1
- package/lib/MessageStreamParser.js.map +1 -0
- package/lib/MessageStreamWriter.js +10 -1
- package/lib/MessageStreamWriter.js.map +1 -0
- package/lib/MessageWriter.js +84 -17
- package/lib/MessageWriter.js.map +1 -0
- package/lib/formats.js +21 -3
- package/lib/formats.js.map +1 -0
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -0
- package/package.json +42 -14
- package/src/MessageParser.js +35 -3
- package/src/MessageParserCore.js +43 -11
- package/src/MessageStreamParser.js +8 -0
- package/src/MessageStreamWriter.js +6 -0
- package/src/MessageWriter.js +80 -18
- package/src/browser.js +61 -0
- package/src/formats.js +17 -2
- package/src/internal.d.ts +15 -0
- package/lib/MessageScanner.js +0 -395
package/lib/MessageWriter.js
CHANGED
|
@@ -16,6 +16,7 @@ var _formats = require("./formats.js");
|
|
|
16
16
|
// (current graph, subject, predicate) leaks from one message into the next, and trailing
|
|
17
17
|
// empty messages survive a round trip (a delimiter before the end of the input does not create a message).
|
|
18
18
|
|
|
19
|
+
/** @extends {Writer<import('@rdfjs/types').BaseQuad>} */
|
|
19
20
|
class LogWriter extends _n.Writer {
|
|
20
21
|
// ### `addDelimiter` ends the current message
|
|
21
22
|
addDelimiter() {
|
|
@@ -23,36 +24,59 @@ class LogWriter extends _n.Writer {
|
|
|
23
24
|
this._write(this._lineMode ? 'MESSAGE\n' : '@message .\n');
|
|
24
25
|
}
|
|
25
26
|
}
|
|
27
|
+
|
|
28
|
+
/** @typedef {import('./internal.js').Done} Done */
|
|
29
|
+
/** @typedef {import('./internal.js').End} End */
|
|
30
|
+
/** @typedef {import('../common.js').MessageWriterOptions} Options */
|
|
31
|
+
/** @typedef {Pick<import('./internal.js').Output, 'write'> & Partial<Pick<import('./internal.js').Output, 'end'>>} Output */
|
|
26
32
|
class MessageWriter {
|
|
27
33
|
// `outputStream` is optional: without it, `end` returns the output as a string
|
|
34
|
+
/** @overload
|
|
35
|
+
* @param {Options} [options] */
|
|
36
|
+
/** @overload
|
|
37
|
+
* @param {Output | null} outputStream
|
|
38
|
+
* @param {Options} [options] */
|
|
39
|
+
/** @param {Output | Options | null} [outputStream]
|
|
40
|
+
* @param {Options} [options] */
|
|
28
41
|
constructor(outputStream, options) {
|
|
29
|
-
if (outputStream && typeof outputStream.write !== 'function') options = outputStream, outputStream = null;
|
|
42
|
+
if (outputStream && typeof /** @type {Output} */outputStream.write !== 'function') options = /** @type {Options} */outputStream, outputStream = null;
|
|
30
43
|
options = options || {};
|
|
31
44
|
this._format = (0, _formats.resolveFormat)(options.format);
|
|
32
45
|
this._options = options;
|
|
33
|
-
this._version = options.version
|
|
46
|
+
this._version = options.version ?? this._format.version ?? '1.2-messages';
|
|
34
47
|
if (!(0, _formats.isMessagesVersion)(this._version) || !(0, _formats.isSupportedVersion)((0, _formats.baseVersion)(this._version))) throw new TypeError(`Unsupported RDF Messages version: "${this._version}"`);
|
|
35
48
|
this._output = '';
|
|
36
|
-
this._stream = outputStream;
|
|
49
|
+
this._stream = /** @type {Output | null | undefined} */outputStream;
|
|
37
50
|
this._endStream = !outputStream || options.end !== false;
|
|
38
51
|
this._pending = 0;
|
|
52
|
+
|
|
53
|
+
/** @type {Done[]} */
|
|
39
54
|
this._waiting = [];
|
|
55
|
+
|
|
56
|
+
/** @type {Error | null} */
|
|
40
57
|
this._error = null;
|
|
41
58
|
this._started = false;
|
|
42
59
|
this._ended = false;
|
|
43
60
|
this._open = false;
|
|
44
61
|
this._count = 0; // messages begun so far: the index of the next message
|
|
45
62
|
this._declared = Object.assign({}, options.prefixes);
|
|
63
|
+
|
|
64
|
+
/** @type {Record<string, string>} */
|
|
46
65
|
this._newPrefixes = {};
|
|
47
66
|
// The N3.js writer writes to this sink, which it never ends
|
|
67
|
+
/** @type {Pick<Output, 'write'>} */
|
|
48
68
|
this._sink = {
|
|
49
69
|
write: (chunk, encoding, done) => this._write(chunk, done)
|
|
50
70
|
};
|
|
71
|
+
|
|
72
|
+
/** @type {LogWriter | null} */
|
|
51
73
|
this._writer = null;
|
|
52
74
|
}
|
|
53
75
|
|
|
54
76
|
// ### `addMessage` writes the quads of one message, followed by a delimiter.
|
|
55
77
|
// The callback (or returned promise) completes once the output is flushed.
|
|
78
|
+
/** @param {import('@rdfjs/types').BaseQuad[]} quads
|
|
79
|
+
* @param {Done} [done] */
|
|
56
80
|
addMessage(quads, done) {
|
|
57
81
|
return this._complete(done, () => {
|
|
58
82
|
if (this._open) throw new Error('A message is already open');
|
|
@@ -63,6 +87,7 @@ class MessageWriter {
|
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
// ### `beginMessage` opens a message. It is optional: the first `addQuad` opens one implicitly.
|
|
90
|
+
/** @param {Done} [done] */
|
|
66
91
|
beginMessage(done) {
|
|
67
92
|
return this._complete(done, () => {
|
|
68
93
|
if (this._open) throw new Error('A message is already open');
|
|
@@ -73,6 +98,9 @@ class MessageWriter {
|
|
|
73
98
|
// ### `addQuad` writes a quad into the open message right away (a message is opened if there is none).
|
|
74
99
|
// With a `messageIndex` (0-based), a change of index ends the current message and writes the empty
|
|
75
100
|
// messages in between, as rdf-writer-ts does; a lower index than the current one is an error.
|
|
101
|
+
/** @param {import('@rdfjs/types').BaseQuad} quad
|
|
102
|
+
* @param {number | Done} [messageIndex]
|
|
103
|
+
* @param {Done} [done] */
|
|
76
104
|
addQuad(quad, messageIndex, done) {
|
|
77
105
|
if (typeof messageIndex === 'function') done = messageIndex, messageIndex = undefined;
|
|
78
106
|
return this._complete(done, () => {
|
|
@@ -82,6 +110,7 @@ class MessageWriter {
|
|
|
82
110
|
}
|
|
83
111
|
|
|
84
112
|
// ### `endMessage` ends the open message with a delimiter. Without an open message, it writes an empty one.
|
|
113
|
+
/** @param {Done} [done] */
|
|
85
114
|
endMessage(done) {
|
|
86
115
|
return this._complete(done, () => {
|
|
87
116
|
if (!this._open) this._begin();
|
|
@@ -91,14 +120,24 @@ class MessageWriter {
|
|
|
91
120
|
|
|
92
121
|
// ### `addPrefix` declares a prefix, which is written before the next message
|
|
93
122
|
// and stays in effect for all messages after it
|
|
123
|
+
/** @param {string} prefix
|
|
124
|
+
* @param {string | import('@rdfjs/types').NamedNode} iri
|
|
125
|
+
* @param {Done} [done] */
|
|
94
126
|
addPrefix(prefix, iri, done) {
|
|
95
127
|
return this._complete(done, () => {
|
|
96
|
-
if (!this._format.lineMode && this._declared[prefix] !== (iri
|
|
128
|
+
if (!this._format.lineMode && this._declared[prefix] !== (typeof iri === 'string' ? iri : iri.value)) this._newPrefixes[prefix] = typeof iri === 'string' ? iri : iri.value;
|
|
97
129
|
});
|
|
98
130
|
}
|
|
99
131
|
|
|
100
132
|
// ### `end` ends the log and, unless disabled, the output stream.
|
|
101
133
|
// The callback receives the output as a string if no output stream was given.
|
|
134
|
+
/** @overload
|
|
135
|
+
* @returns {Promise<string | void>} */
|
|
136
|
+
/** @overload
|
|
137
|
+
* @param {End} done
|
|
138
|
+
* @returns {void} */
|
|
139
|
+
/** @param {End} [done]
|
|
140
|
+
* @returns {Promise<string | void> | void} */
|
|
102
141
|
end(done) {
|
|
103
142
|
// Ending twice is harmless
|
|
104
143
|
if (this._ended) return typeof done === 'function' ? done(null) : Promise.resolve();
|
|
@@ -111,40 +150,53 @@ class MessageWriter {
|
|
|
111
150
|
// ## Private methods
|
|
112
151
|
|
|
113
152
|
// Runs an action and reports completion with a callback or a promise
|
|
153
|
+
/** @param {Done | undefined} done
|
|
154
|
+
* @param {() => void} action
|
|
155
|
+
* @returns {Promise<void> | void} */
|
|
114
156
|
_complete(done, action) {
|
|
115
157
|
if (this._ended) this._error = this._error || new Error('Cannot write after end');else try {
|
|
116
158
|
action();
|
|
117
159
|
} catch (error) {
|
|
118
|
-
this._error = this._error || error;
|
|
160
|
+
this._error = this._error || (/** @type {Error} */error);
|
|
119
161
|
}
|
|
120
162
|
if (typeof done === 'function') return this._whenFlushed(done);
|
|
121
163
|
return new Promise((resolve, reject) => this._whenFlushed(error => error ? reject(error) : resolve()));
|
|
122
164
|
}
|
|
123
165
|
|
|
124
166
|
// Ends the output once all queued writes were accepted
|
|
167
|
+
/** @param {End} callback */
|
|
125
168
|
_finish(callback) {
|
|
126
169
|
this._ended = true;
|
|
127
170
|
this._whenFlushed(error => this._endOutput(error, callback));
|
|
128
171
|
}
|
|
172
|
+
|
|
173
|
+
/** @param {Error | null | undefined} error
|
|
174
|
+
* @param {End} callback */
|
|
129
175
|
_endOutput(error, callback) {
|
|
130
176
|
if (error || !this._endStream) return callback(error);
|
|
131
177
|
if (!this._stream) return callback(null, this._output);
|
|
132
178
|
try {
|
|
133
|
-
this._stream.end(endError => callback(endError));
|
|
179
|
+
(/** @type {Required<Output>} */this._stream).end(endError => callback(endError));
|
|
134
180
|
} catch (endError) {
|
|
135
|
-
callback(endError);
|
|
181
|
+
callback(/** @type {Error} */endError);
|
|
136
182
|
}
|
|
137
183
|
}
|
|
138
184
|
|
|
139
185
|
// Calls back once all queued writes were accepted by the output
|
|
186
|
+
/** @param {Done} done */
|
|
140
187
|
_whenFlushed(done) {
|
|
141
188
|
if (this._pending === 0) this._settle(done);else this._waiting.push(done);
|
|
142
189
|
}
|
|
190
|
+
|
|
191
|
+
/** @param {Done} done */
|
|
143
192
|
_settle(done) {
|
|
144
193
|
const error = this._error;
|
|
145
194
|
this._error = null;
|
|
146
195
|
done(error || null);
|
|
147
196
|
}
|
|
197
|
+
|
|
198
|
+
/** @param {string} chunk
|
|
199
|
+
* @param {Done} [done] */
|
|
148
200
|
_write(chunk, done) {
|
|
149
201
|
if (!this._stream) {
|
|
150
202
|
this._output += chunk;
|
|
@@ -154,11 +206,13 @@ class MessageWriter {
|
|
|
154
206
|
try {
|
|
155
207
|
this._stream.write(chunk, 'utf8', error => this._written(error, done));
|
|
156
208
|
} catch (error) {
|
|
157
|
-
this._written(error, done);
|
|
209
|
+
this._written(/** @type {Error} */error, done);
|
|
158
210
|
}
|
|
159
211
|
}
|
|
160
212
|
|
|
161
213
|
// Registers that the output accepted a write, and wakes up those waiting for the output
|
|
214
|
+
/** @param {Error | null | undefined} error
|
|
215
|
+
* @param {Done} [done] */
|
|
162
216
|
_written(error, done) {
|
|
163
217
|
this._pending--;
|
|
164
218
|
this._error = this._error || error || null;
|
|
@@ -175,7 +229,7 @@ class MessageWriter {
|
|
|
175
229
|
this._writer = new LogWriter(this._sink, {
|
|
176
230
|
format: this._format.name,
|
|
177
231
|
end: false,
|
|
178
|
-
version: this._version,
|
|
232
|
+
version: options.writeVersion === false ? undefined : this._version,
|
|
179
233
|
baseIRI: options.baseIRI,
|
|
180
234
|
writeBase: options.writeBase,
|
|
181
235
|
prefixes: this._declared
|
|
@@ -186,25 +240,30 @@ class MessageWriter {
|
|
|
186
240
|
// Opens a message: declares the prefixes that were added since the previous one
|
|
187
241
|
_begin() {
|
|
188
242
|
this._start();
|
|
189
|
-
const writer = this._writer;
|
|
243
|
+
const writer = /** @type {LogWriter} */this._writer;
|
|
190
244
|
for (const prefix of Object.keys(this._newPrefixes)) {
|
|
191
|
-
|
|
192
|
-
|
|
245
|
+
const iri = /** @type {string} */this._newPrefixes[prefix];
|
|
246
|
+
writer.addPrefix(prefix, iri);
|
|
247
|
+
this._declared[prefix] = iri;
|
|
193
248
|
}
|
|
194
249
|
this._newPrefixes = {};
|
|
195
250
|
this._open = true;
|
|
196
251
|
this._count++;
|
|
197
252
|
}
|
|
253
|
+
|
|
254
|
+
/** @param {import('@rdfjs/types').BaseQuad} quad */
|
|
198
255
|
_add(quad) {
|
|
256
|
+
/** @type {Done} */
|
|
199
257
|
const record = error => error && (this._error = this._error || error);
|
|
200
|
-
this._writer.addQuad(quad.subject, quad.predicate, quad.object, quad.graph, record);
|
|
258
|
+
(/** @type {LogWriter} */this._writer).addQuad(quad.subject, quad.predicate, quad.object, quad.graph, record);
|
|
201
259
|
}
|
|
202
260
|
_close() {
|
|
203
261
|
this._open = false;
|
|
204
|
-
this._writer.addDelimiter();
|
|
262
|
+
(/** @type {LogWriter} */this._writer).addDelimiter();
|
|
205
263
|
}
|
|
206
264
|
|
|
207
265
|
// Makes message `index` the open message, writing empty messages for the gap
|
|
266
|
+
/** @param {number} index */
|
|
208
267
|
_moveTo(index) {
|
|
209
268
|
const current = this._count - 1;
|
|
210
269
|
if (!Number.isInteger(index) || index < 0) throw new RangeError(`Invalid message index: ${index}`);
|
|
@@ -219,17 +278,25 @@ class MessageWriter {
|
|
|
219
278
|
}
|
|
220
279
|
}
|
|
221
280
|
|
|
281
|
+
/** @param {Iterable<import('@rdfjs/types').BaseQuad[]>} messages
|
|
282
|
+
* @param {Options} [options]
|
|
283
|
+
* @returns {string} */
|
|
222
284
|
// ### `writeMessages` synchronously serializes an array of messages to a string
|
|
223
285
|
exports.default = MessageWriter;
|
|
224
286
|
function writeMessages(messages, options) {
|
|
225
287
|
const writer = new MessageWriter(options);
|
|
288
|
+
|
|
289
|
+
/** @type {Error[]} */
|
|
226
290
|
const errors = [];
|
|
227
|
-
let output;
|
|
291
|
+
let output = '';
|
|
292
|
+
|
|
293
|
+
/** @param {Error | null | undefined} error */
|
|
228
294
|
function collect(error) {
|
|
229
295
|
if (error) errors.push(error);
|
|
230
296
|
}
|
|
231
297
|
for (const message of messages) writer.addMessage(message, collect);
|
|
232
|
-
writer.end((error, result) => (collect(error), output = result));
|
|
298
|
+
writer.end((error, result) => (collect(error), output = /** @type {string} */result));
|
|
233
299
|
if (errors.length > 0) throw errors[0];
|
|
234
300
|
return output;
|
|
235
|
-
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=MessageWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageWriter.js","names":["Writer","resolveFormat","isMessagesVersion","isSupportedVersion","baseVersion"],"sources":["../src/MessageWriter.js"],"sourcesContent":["// **MessageWriter** writes RDF Message Logs (Turtle, TriG, N-Triples and N-Quads).\n//\n// One N3.js writer writes the whole log: its `version` option announces the log,\n// and after each message, `_endStatement` finishes the pending statement (and graph block)\n// before a delimiter is written (`MESSAGE` in line formats, `@message .` in Turtle and TriG).\n// That way, consumers receive a message as soon as it is written, no serialization state\n// (current graph, subject, predicate) leaks from one message into the next, and trailing\n// empty messages survive a round trip (a delimiter before the end of the input does not create a message).\nimport { Writer } from 'n3';\nimport { resolveFormat, isMessagesVersion, baseVersion, isSupportedVersion } from './formats.js';\n\n/** @extends {Writer<import('@rdfjs/types').BaseQuad>} */\nclass LogWriter extends Writer {\n // ### `addDelimiter` ends the current message\n addDelimiter() {\n this._endStatement();\n this._write(this._lineMode ? 'MESSAGE\\n' : '@message .\\n');\n }\n}\n\n/** @typedef {import('./internal.js').Done} Done */\n/** @typedef {import('./internal.js').End} End */\n/** @typedef {import('../common.js').MessageWriterOptions} Options */\n/** @typedef {Pick<import('./internal.js').Output, 'write'> & Partial<Pick<import('./internal.js').Output, 'end'>>} Output */\nexport default class MessageWriter {\n // `outputStream` is optional: without it, `end` returns the output as a string\n /** @overload\n * @param {Options} [options] */\n /** @overload\n * @param {Output | null} outputStream\n * @param {Options} [options] */\n /** @param {Output | Options | null} [outputStream]\n * @param {Options} [options] */\n constructor(outputStream, options) {\n if (outputStream && typeof /** @type {Output} */ (outputStream).write !== 'function')\n options = /** @type {Options} */ (outputStream), outputStream = null;\n options = options || {};\n this._format = resolveFormat(options.format);\n this._options = options;\n this._version = options.version ?? this._format.version ?? '1.2-messages';\n if (!isMessagesVersion(this._version) || !isSupportedVersion(baseVersion(this._version)))\n throw new TypeError(`Unsupported RDF Messages version: \"${this._version}\"`);\n\n this._output = '';\n this._stream = /** @type {Output | null | undefined} */ (outputStream);\n this._endStream = !outputStream || options.end !== false;\n this._pending = 0;\n\n /** @type {Done[]} */\n this._waiting = [];\n\n /** @type {Error | null} */\n this._error = null;\n this._started = false;\n this._ended = false;\n this._open = false;\n this._count = 0; // messages begun so far: the index of the next message\n this._declared = Object.assign({}, options.prefixes);\n\n /** @type {Record<string, string>} */\n this._newPrefixes = {};\n // The N3.js writer writes to this sink, which it never ends\n /** @type {Pick<Output, 'write'>} */\n this._sink = { write: (chunk, encoding, done) => this._write(chunk, done) };\n\n /** @type {LogWriter | null} */\n this._writer = null;\n }\n\n // ### `addMessage` writes the quads of one message, followed by a delimiter.\n // The callback (or returned promise) completes once the output is flushed.\n /** @param {import('@rdfjs/types').BaseQuad[]} quads\n * @param {Done} [done] */\n addMessage(quads, done) {\n return this._complete(done, () => {\n if (this._open) throw new Error('A message is already open');\n this._begin();\n for (const quad of quads || []) this._add(quad);\n this._close();\n });\n }\n\n // ### `beginMessage` opens a message. It is optional: the first `addQuad` opens one implicitly.\n /** @param {Done} [done] */\n beginMessage(done) {\n return this._complete(done, () => {\n if (this._open) throw new Error('A message is already open');\n this._begin();\n });\n }\n\n // ### `addQuad` writes a quad into the open message right away (a message is opened if there is none).\n // With a `messageIndex` (0-based), a change of index ends the current message and writes the empty\n // messages in between, as rdf-writer-ts does; a lower index than the current one is an error.\n /** @param {import('@rdfjs/types').BaseQuad} quad\n * @param {number | Done} [messageIndex]\n * @param {Done} [done] */\n addQuad(quad, messageIndex, done) {\n if (typeof messageIndex === 'function') done = messageIndex, messageIndex = undefined;\n return this._complete(done, () => {\n if (messageIndex !== undefined && messageIndex !== null) this._moveTo(messageIndex);\n else if (!this._open) this._begin();\n this._add(quad);\n });\n }\n\n // ### `endMessage` ends the open message with a delimiter. Without an open message, it writes an empty one.\n /** @param {Done} [done] */\n endMessage(done) {\n return this._complete(done, () => {\n if (!this._open) this._begin();\n this._close();\n });\n }\n\n // ### `addPrefix` declares a prefix, which is written before the next message\n // and stays in effect for all messages after it\n /** @param {string} prefix\n * @param {string | import('@rdfjs/types').NamedNode} iri\n * @param {Done} [done] */\n addPrefix(prefix, iri, done) {\n return this._complete(done, () => {\n if (!this._format.lineMode && this._declared[prefix] !== (typeof iri === 'string' ? iri : iri.value))\n this._newPrefixes[prefix] = typeof iri === 'string' ? iri : iri.value;\n });\n }\n\n // ### `end` ends the log and, unless disabled, the output stream.\n // The callback receives the output as a string if no output stream was given.\n /** @overload\n * @returns {Promise<string | void>} */\n /** @overload\n * @param {End} done\n * @returns {void} */\n /** @param {End} [done]\n * @returns {Promise<string | void> | void} */\n end(done) {\n // Ending twice is harmless\n if (this._ended)\n return typeof done === 'function' ? done(null) : Promise.resolve();\n this._start();\n if (this._open)\n this._close();\n if (typeof done === 'function')\n return this._finish(done);\n return new Promise((resolve, reject) => this._finish((error, result) => error ? reject(error) : resolve(result)));\n }\n\n // ## Private methods\n\n // Runs an action and reports completion with a callback or a promise\n /** @param {Done | undefined} done\n * @param {() => void} action\n * @returns {Promise<void> | void} */\n _complete(done, action) {\n if (this._ended)\n this._error = this._error || new Error('Cannot write after end');\n else\n try {\n action();\n }\n catch (error) {\n this._error = this._error || /** @type {Error} */ (error);\n }\n if (typeof done === 'function')\n return this._whenFlushed(done);\n return new Promise((resolve, reject) => this._whenFlushed(error => error ? reject(error) : resolve()));\n }\n\n // Ends the output once all queued writes were accepted\n /** @param {End} callback */\n _finish(callback) {\n this._ended = true;\n this._whenFlushed(error => this._endOutput(error, callback));\n }\n\n /** @param {Error | null | undefined} error\n * @param {End} callback */\n _endOutput(error, callback) {\n if (error || !this._endStream)\n return callback(error);\n if (!this._stream)\n return callback(null, this._output);\n try {\n (/** @type {Required<Output>} */ (this._stream)).end(endError => callback(endError));\n }\n catch (endError) {\n callback(/** @type {Error} */ (endError));\n }\n }\n\n // Calls back once all queued writes were accepted by the output\n /** @param {Done} done */\n _whenFlushed(done) {\n if (this._pending === 0)\n this._settle(done);\n else\n this._waiting.push(done);\n }\n\n /** @param {Done} done */\n _settle(done) {\n const error = this._error;\n this._error = null;\n done(error || null);\n }\n\n /** @param {string} chunk\n * @param {Done} [done] */\n _write(chunk, done) {\n if (!this._stream) {\n this._output += chunk;\n return done && done();\n }\n this._pending++;\n try {\n this._stream.write(chunk, 'utf8', error => this._written(error, done));\n }\n catch (error) {\n this._written(/** @type {Error} */ (error), done);\n }\n }\n\n // Registers that the output accepted a write, and wakes up those waiting for the output\n /** @param {Error | null | undefined} error\n * @param {Done} [done] */\n _written(error, done) {\n this._pending--;\n this._error = this._error || error || null;\n done && done(error);\n if (this._pending === 0)\n this._waiting.splice(0).forEach(callback => this._settle(callback));\n }\n\n // Announces the RDF Messages version, which makes parsers expect delimiters,\n // and declares the base and prefixes, which stay in effect for all messages\n _start() {\n if (!this._started) {\n this._started = true;\n const options = this._options;\n this._writer = new LogWriter(this._sink, {\n format: this._format.name,\n end: false,\n version: options.writeVersion === false ? undefined : this._version,\n baseIRI: options.baseIRI,\n writeBase: options.writeBase,\n prefixes: this._declared,\n });\n }\n }\n\n // Opens a message: declares the prefixes that were added since the previous one\n _begin() {\n this._start();\n const writer = /** @type {LogWriter} */ (this._writer);\n for (const prefix of Object.keys(this._newPrefixes)) {\n const iri = /** @type {string} */ (this._newPrefixes[prefix]);\n writer.addPrefix(prefix, iri);\n this._declared[prefix] = iri;\n }\n this._newPrefixes = {};\n this._open = true;\n this._count++;\n }\n\n /** @param {import('@rdfjs/types').BaseQuad} quad */\n _add(quad) {\n /** @type {Done} */\n const record = error => error && (this._error = this._error || error);\n (/** @type {LogWriter} */ (this._writer)).addQuad(quad.subject, quad.predicate, quad.object, quad.graph, record);\n }\n _close() {\n this._open = false;\n (/** @type {LogWriter} */ (this._writer)).addDelimiter();\n }\n\n // Makes message `index` the open message, writing empty messages for the gap\n /** @param {number} index */\n _moveTo(index) {\n const current = this._count - 1;\n if (!Number.isInteger(index) || index < 0) throw new RangeError(`Invalid message index: ${index}`);\n if (this._open && index === current) return;\n if (index <= current) throw new RangeError(`Message index ${index} is lower than the current message index ${current}`);\n if (this._open) this._close();\n while (this._count < index) {\n this._begin();\n this._close();\n }\n this._begin();\n }\n}\n\n/** @param {Iterable<import('@rdfjs/types').BaseQuad[]>} messages\n * @param {Options} [options]\n * @returns {string} */\n// ### `writeMessages` synchronously serializes an array of messages to a string\nexport function writeMessages(messages, options) {\n const writer = new MessageWriter(options);\n\n /** @type {Error[]} */\n const errors = [];\n let output = '';\n\n /** @param {Error | null | undefined} error */\n function collect(error) {\n if (error)\n errors.push(error);\n }\n for (const message of messages)\n writer.addMessage(message, collect);\n writer.end((error, result) => (collect(error), output = /** @type {string} */ (result)));\n if (errors.length > 0)\n throw errors[0];\n return output;\n}\n"],"mappings":"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","ignoreList":[]}
|
package/lib/formats.js
CHANGED
|
@@ -9,6 +9,7 @@ exports.isSupportedVersion = isSupportedVersion;
|
|
|
9
9
|
exports.resolveFormat = resolveFormat;
|
|
10
10
|
// **formats** describes the RDF syntaxes that support RDF Messages.
|
|
11
11
|
|
|
12
|
+
/** @type {Record<string, { name: string; lineMode: boolean }>} */
|
|
12
13
|
const FORMATS = {
|
|
13
14
|
turtle: {
|
|
14
15
|
name: 'Turtle',
|
|
@@ -32,24 +33,41 @@ const FORMATS = {
|
|
|
32
33
|
const BASE_VERSIONS = ['1.2', '1.2-basic', '1.1'];
|
|
33
34
|
|
|
34
35
|
// ### `resolveFormat` maps a format name or media type to a supported syntax
|
|
36
|
+
/** @returns {{ name: string; lineMode: boolean; version?: string }} */
|
|
35
37
|
function resolveFormat(format = 'TriG') {
|
|
36
|
-
const key = String(format).toLowerCase().
|
|
38
|
+
const key = String(format).toLowerCase().replace(/;[\s\S]*$/, '').trim().replace(/^(?:text|application)\//, '').replace(/^x-/, '').replace(/[-_ ]/g, '');
|
|
37
39
|
const resolved = FORMATS[key];
|
|
38
40
|
if (!resolved) throw new TypeError(`Unsupported RDF Messages format: "${format}". ` + 'Supported formats are Turtle, TriG, N-Triples and N-Quads.');
|
|
39
|
-
|
|
41
|
+
let version;
|
|
42
|
+
// Consume quoted values whole, so a semicolon inside another parameter cannot
|
|
43
|
+
// accidentally introduce a version parameter. Parameter names are case-insensitive.
|
|
44
|
+
for (const parameter of String(format).matchAll(/;\s*([^;=\s]+)\s*=\s*("(?:[^"\\]|\\.)*"|[^;]*)\s*(?=;|$)/g)) {
|
|
45
|
+
if (/** @type {string} */parameter[1].toLowerCase() === 'version') {
|
|
46
|
+
if (version !== undefined) throw new TypeError('Duplicate RDF version parameter.');
|
|
47
|
+
version = /** @type {string} */parameter[2].trim().replace(/^"(.*)"$/, '$1').replace(/\\(.)/g, '$1');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return version === undefined ? resolved : {
|
|
51
|
+
...resolved,
|
|
52
|
+
version
|
|
53
|
+
};
|
|
40
54
|
}
|
|
41
55
|
|
|
56
|
+
/** @param {unknown} version */
|
|
42
57
|
// ### `isMessagesVersion` checks whether a version label announces RDF Messages
|
|
43
58
|
function isMessagesVersion(version) {
|
|
44
59
|
return typeof version === 'string' && version.endsWith('-messages');
|
|
45
60
|
}
|
|
46
61
|
|
|
62
|
+
/** @param {string} version */
|
|
47
63
|
// ### `baseVersion` strips the `-messages` suffix of a version label
|
|
48
64
|
function baseVersion(version) {
|
|
49
65
|
return isMessagesVersion(version) ? version.slice(0, -'-messages'.length) : version;
|
|
50
66
|
}
|
|
51
67
|
|
|
68
|
+
/** @param {string} version */
|
|
52
69
|
// ### `isSupportedVersion` checks whether a (base) version label is supported
|
|
53
70
|
function isSupportedVersion(version, supported = BASE_VERSIONS) {
|
|
54
71
|
return supported.includes(version);
|
|
55
|
-
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=formats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formats.js","names":[],"sources":["../src/formats.js"],"sourcesContent":["// **formats** describes the RDF syntaxes that support RDF Messages.\n\n/** @type {Record<string, { name: string; lineMode: boolean }>} */\nconst FORMATS = {\n turtle: { name: 'Turtle', lineMode: false },\n trig: { name: 'TriG', lineMode: false },\n ntriples: { name: 'N-Triples', lineMode: true },\n nquads: { name: 'N-Quads', lineMode: true },\n};\n\n// The version labels of RDF 1.2 syntaxes, as accepted by N3.js\nconst BASE_VERSIONS = ['1.2', '1.2-basic', '1.1'];\n\n// ### `resolveFormat` maps a format name or media type to a supported syntax\n/** @returns {{ name: string; lineMode: boolean; version?: string }} */\nexport function resolveFormat(format = 'TriG') {\n const key = String(format).toLowerCase().replace(/;[\\s\\S]*$/, '').trim()\n .replace(/^(?:text|application)\\//, '')\n .replace(/^x-/, '')\n .replace(/[-_ ]/g, '');\n const resolved = FORMATS[key];\n if (!resolved)\n throw new TypeError(`Unsupported RDF Messages format: \"${format}\". ` +\n 'Supported formats are Turtle, TriG, N-Triples and N-Quads.');\n let version;\n // Consume quoted values whole, so a semicolon inside another parameter cannot\n // accidentally introduce a version parameter. Parameter names are case-insensitive.\n for (const parameter of String(format).matchAll(/;\\s*([^;=\\s]+)\\s*=\\s*(\"(?:[^\"\\\\]|\\\\.)*\"|[^;]*)\\s*(?=;|$)/g)) {\n if (/** @type {string} */ (parameter[1]).toLowerCase() === 'version') {\n if (version !== undefined)\n throw new TypeError('Duplicate RDF version parameter.');\n version = /** @type {string} */ (parameter[2]).trim().replace(/^\"(.*)\"$/, '$1').replace(/\\\\(.)/g, '$1');\n }\n }\n return version === undefined ? resolved : { ...resolved, version };\n}\n\n/** @param {unknown} version */\n// ### `isMessagesVersion` checks whether a version label announces RDF Messages\nexport function isMessagesVersion(version) {\n return typeof version === 'string' && version.endsWith('-messages');\n}\n\n/** @param {string} version */\n// ### `baseVersion` strips the `-messages` suffix of a version label\nexport function baseVersion(version) {\n return isMessagesVersion(version) ? version.slice(0, -'-messages'.length) : version;\n}\n\n/** @param {string} version */\n// ### `isSupportedVersion` checks whether a (base) version label is supported\nexport function isSupportedVersion(version, supported = BASE_VERSIONS) {\n return supported.includes(version);\n}\n"],"mappings":";;;;;;;;;AAAA;;AAEA;AACA,MAAM,OAAO,GAAG;EACd,MAAM,EAAE;IAAE,IAAI,EAAE,QAAQ;IAAE,QAAQ,EAAE;EAAM,CAAC;EAC3C,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM;IAAE,QAAQ,EAAE;EAAM,CAAC;EACvC,QAAQ,EAAE;IAAE,IAAI,EAAE,WAAW;IAAE,QAAQ,EAAE;EAAK,CAAC;EAC/C,MAAM,EAAE;IAAE,IAAI,EAAE,SAAS;IAAE,QAAQ,EAAE;EAAK;AAC5C,CAAC;;AAED;AACA,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC;;AAEjD;AACA;AACO,SAAS,aAAa,CAAC,MAAM,GAAG,MAAM,EAAE;EAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CACrE,OAAO,CAAC,yBAAyB,EAAE,EAAE,CAAC,CACtC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAClB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;EACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;EAC7B,IAAI,CAAC,QAAQ,EACX,MAAM,IAAI,SAAS,CAAC,qCAAqC,MAAM,KAAK,GAChD,4DAA4D,CAAC;EACnF,IAAI,OAAO;EACX;EACA;EACA,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,2DAA2D,CAAC,EAAE;IAC5G,IAAI,qBAAuB,SAAS,CAAC,CAAC,CAAC,CAAE,WAAW,CAAC,CAAC,KAAK,SAAS,EAAE;MACpE,IAAI,OAAO,KAAK,SAAS,EACvB,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC;MACzD,OAAO,GAAG,qBAAuB,SAAS,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC;IACzG;EACF;EACA,OAAO,OAAO,KAAK,SAAS,GAAG,QAAQ,GAAG;IAAE,GAAG,QAAQ;IAAE;EAAQ,CAAC;AACpE;;AAEA;AACA;AACO,SAAS,iBAAiB,CAAC,OAAO,EAAE;EACzC,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;AACrE;;AAEA;AACA;AACO,SAAS,WAAW,CAAC,OAAO,EAAE;EACnC,OAAO,iBAAiB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO;AACrF;;AAEA;AACA;AACO,SAAS,kBAAkB,CAAC,OAAO,EAAE,SAAS,GAAG,aAAa,EAAE;EACrE,OAAO,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;AACpC","ignoreList":[]}
|
package/lib/index.js
CHANGED
|
@@ -45,4 +45,5 @@ var _MessageWriter = _interopRequireWildcard(require("./MessageWriter.js"));
|
|
|
45
45
|
var _MessageStreamWriter = _interopRequireDefault(require("./MessageStreamWriter.js"));
|
|
46
46
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
47
47
|
var cache;
|
|
48
|
-
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
|
|
48
|
+
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.js"],"sourcesContent":["export { default as MessageParser, parseMessages } from './MessageParser.js';\nexport { default as MessageStreamParser } from './MessageStreamParser.js';\nexport { default as MessageWriter, writeMessages } from './MessageWriter.js';\nexport { default as MessageStreamWriter } from './MessageStreamWriter.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AAA0E;AAAA;AAAA","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n3.js-messages",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "RDF Messages (message-delimited Turtle, TriG, N-Triples and N-Quads) for N3.js: message-aware parser, streaming parser and writer.",
|
|
5
5
|
"author": "Pieter Colpaert",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,20 +21,35 @@
|
|
|
21
21
|
"types": "./index.d.ts",
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
24
|
+
"browser": {
|
|
25
|
+
"types": "./browser.d.ts",
|
|
26
|
+
"default": "./browser/index.js"
|
|
27
|
+
},
|
|
24
28
|
"types": "./index.d.ts",
|
|
25
29
|
"import": "./src/index.js",
|
|
26
30
|
"require": "./lib/index.js"
|
|
27
31
|
},
|
|
28
|
-
"./package.json": "./package.json"
|
|
32
|
+
"./package.json": "./package.json",
|
|
33
|
+
"./browser": {
|
|
34
|
+
"types": "./browser.d.ts",
|
|
35
|
+
"import": "./browser/index.js",
|
|
36
|
+
"default": "./browser/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./browser/global": "./browser/index.global.js"
|
|
29
39
|
},
|
|
30
|
-
"sideEffects":
|
|
40
|
+
"sideEffects": [
|
|
41
|
+
"./browser/index.global.js"
|
|
42
|
+
],
|
|
31
43
|
"engines": {
|
|
32
44
|
"node": ">=18"
|
|
33
45
|
},
|
|
34
46
|
"files": [
|
|
35
47
|
"src",
|
|
36
48
|
"lib",
|
|
37
|
-
"index.d.ts"
|
|
49
|
+
"index.d.ts",
|
|
50
|
+
"browser",
|
|
51
|
+
"browser.d.ts",
|
|
52
|
+
"common.d.ts"
|
|
38
53
|
],
|
|
39
54
|
"peerDependencies": {
|
|
40
55
|
"n3": ">=2.13.7 <3"
|
|
@@ -48,35 +63,47 @@
|
|
|
48
63
|
},
|
|
49
64
|
"homepage": "https://github.com/pietercolpaert/n3.js-messages#readme",
|
|
50
65
|
"scripts": {
|
|
51
|
-
"build": "
|
|
66
|
+
"build": "node scripts/build.js",
|
|
52
67
|
"prepack": "npm run build",
|
|
53
68
|
"test": "jest",
|
|
54
69
|
"coverage": "jest --coverage",
|
|
55
|
-
"lint": "eslint
|
|
70
|
+
"lint": "eslint . && knip",
|
|
56
71
|
"test:spec": "node spec/runner.js",
|
|
57
72
|
"test:spec:earl": "node spec/runner.js --earl > spec/earl-report.ttl",
|
|
58
73
|
"test:types": "tsc -p test/types/tsconfig.json",
|
|
59
74
|
"test:package": "node scripts/test-package.js",
|
|
60
75
|
"perf": "node perf/run.js",
|
|
61
76
|
"perf:compare": "node perf/compare.js",
|
|
62
|
-
"spec:update": "node scripts/update-spec.js"
|
|
77
|
+
"spec:update": "node scripts/update-spec.js",
|
|
78
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
79
|
+
"check": "npm run lint && npm run typecheck && npm run test:types && npm run build && npm test -- --runInBand && npm run test:spec",
|
|
80
|
+
"ci": "npm run check && npm run test:package && npm run test:browser && npm run perf:regression",
|
|
81
|
+
"test:browser": "node scripts/test-browser.js",
|
|
82
|
+
"hooks:install": "node scripts/install-hooks.js",
|
|
83
|
+
"perf:regression": "node perf/regression.js",
|
|
84
|
+
"test:n3-extract": "node scripts/extract-n3-parser-tests.cjs"
|
|
63
85
|
},
|
|
64
86
|
"devDependencies": {
|
|
65
87
|
"@babel/cli": "^8.0.6",
|
|
66
|
-
"@babel/core": "^8.0.
|
|
88
|
+
"@babel/core": "^8.0.9",
|
|
67
89
|
"@babel/preset-env": "^8.0.7",
|
|
68
|
-
"@types/n3": "^1.26.
|
|
69
|
-
"@types/node": "^26.6.
|
|
90
|
+
"@types/n3": "^1.26.5",
|
|
91
|
+
"@types/node": "^26.6.5",
|
|
70
92
|
"babel-jest": "^30.5.2",
|
|
71
|
-
"
|
|
93
|
+
"esbuild": "^0.28.2",
|
|
94
|
+
"eslint": "^10.13.0",
|
|
72
95
|
"eslint-plugin-import-x": "^4.17.1",
|
|
73
|
-
"eslint-plugin-jest": "^29.
|
|
96
|
+
"eslint-plugin-jest": "^29.17.0",
|
|
97
|
+
"events": "^3.3.0",
|
|
74
98
|
"globals": "^17.13.0",
|
|
75
99
|
"jest": "^30.5.2",
|
|
76
|
-
"
|
|
100
|
+
"knip": "^6.43.0",
|
|
101
|
+
"n3": "^2.13.12",
|
|
102
|
+
"playwright": "^1.64.1",
|
|
77
103
|
"rdf-isomorphic": "^2.0.1",
|
|
78
104
|
"rdf-parser-ts": "^0.4.0",
|
|
79
105
|
"rdf-writer-ts": "^0.2.1",
|
|
106
|
+
"string_decoder": "^1.3.0",
|
|
80
107
|
"typescript": "^7.0.2"
|
|
81
108
|
},
|
|
82
109
|
"jest": {
|
|
@@ -103,5 +130,6 @@
|
|
|
103
130
|
},
|
|
104
131
|
"dependencies": {
|
|
105
132
|
"@rdfjs/types": "^2.0.1"
|
|
106
|
-
}
|
|
133
|
+
},
|
|
134
|
+
"browser": "./browser/index.js"
|
|
107
135
|
}
|
package/src/MessageParser.js
CHANGED
|
@@ -2,13 +2,18 @@
|
|
|
2
2
|
import { StringDecoder } from 'string_decoder';
|
|
3
3
|
import MessageParserCore from './MessageParserCore.js';
|
|
4
4
|
|
|
5
|
+
/** @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad] */
|
|
5
6
|
export default class MessageParser {
|
|
7
|
+
/** @param {import('../common.js').MessageParserOptions<Q>} [options] */
|
|
6
8
|
constructor(options) {
|
|
9
|
+
/** @type {import('../common.js').MessageParserOptions<Q>} */
|
|
7
10
|
this._options = options || {};
|
|
8
11
|
// Fail early on unsupported options
|
|
9
|
-
this.
|
|
12
|
+
// Construction only validates options; this core never receives input.
|
|
13
|
+
this._createCore(/** @type {import('./internal.js').ParserSink<Q>} */ ({}));
|
|
10
14
|
}
|
|
11
15
|
|
|
16
|
+
/** @param {import('./internal.js').ParserSink<Q>} sink */
|
|
12
17
|
_createCore(sink) {
|
|
13
18
|
return new MessageParserCore(this._options, sink);
|
|
14
19
|
}
|
|
@@ -21,23 +26,45 @@ export default class MessageParser {
|
|
|
21
26
|
// callbacks `onMessage(error, message, prefixes)`, `onQuad(error, quad, messageIndex)`,
|
|
22
27
|
// `onPrefix(prefix, term)` and `onVersion(label)`, messages are reported as soon
|
|
23
28
|
// as they are complete. The final call has `null` as message.
|
|
29
|
+
/**
|
|
30
|
+
* @overload
|
|
31
|
+
* @param {string} input
|
|
32
|
+
* @returns {Q[][]}
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* @overload
|
|
36
|
+
* @param {string | NodeJS.ReadableStream} input
|
|
37
|
+
* @param {import('../common.js').MessageCallback<Q> | import('../common.js').MessageParseCallbacks<Q>} [callbacks]
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* @param {string | NodeJS.ReadableStream} input
|
|
42
|
+
* @param {import('../common.js').MessageCallback<Q> | import('../common.js').MessageParseCallbacks<Q>} [callbacks]
|
|
43
|
+
* @returns {Q[][] | undefined}
|
|
44
|
+
*/
|
|
24
45
|
parse(input, callbacks) {
|
|
25
46
|
if (typeof callbacks === 'function')
|
|
26
47
|
callbacks = { onMessage: callbacks };
|
|
48
|
+
|
|
49
|
+
/** @type {Q[][] | null} */
|
|
27
50
|
const messages = callbacks ? null : [];
|
|
51
|
+
|
|
52
|
+
/** @type {Error | null} */
|
|
28
53
|
let error = null;
|
|
29
54
|
callbacks = callbacks || {};
|
|
55
|
+
|
|
56
|
+
/** @type {import('./internal.js').ParserSink<Q>} */
|
|
30
57
|
const sink = {
|
|
31
58
|
message: (quads, index) => callbacks.onMessage ? callbacks.onMessage(null, quads, undefined, index) : messages && messages.push(quads),
|
|
32
59
|
end: prefixes => callbacks.onMessage && callbacks.onMessage(null, null, prefixes),
|
|
33
60
|
error: e => {
|
|
34
61
|
error = e;
|
|
35
|
-
callbacks.onMessage && callbacks.onMessage(e);
|
|
62
|
+
callbacks.onMessage && callbacks.onMessage(e, null);
|
|
36
63
|
callbacks.onQuad && callbacks.onQuad(e);
|
|
37
64
|
},
|
|
38
65
|
};
|
|
39
66
|
if (callbacks.onQuad)
|
|
40
|
-
sink.quad = (quad, index) => callbacks.onQuad(null, quad, index);
|
|
67
|
+
sink.quad = (quad, index) => callbacks.onQuad?.(null, quad, index);
|
|
41
68
|
if (callbacks.onPrefix)
|
|
42
69
|
sink.prefix = callbacks.onPrefix;
|
|
43
70
|
if (callbacks.onVersion)
|
|
@@ -65,6 +92,11 @@ export default class MessageParser {
|
|
|
65
92
|
}
|
|
66
93
|
}
|
|
67
94
|
|
|
95
|
+
/**
|
|
96
|
+
* @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad]
|
|
97
|
+
* @param {string} input
|
|
98
|
+
* @param {import('../common.js').MessageParserOptions<Q>} [options]
|
|
99
|
+
*/
|
|
68
100
|
// ### `parseMessages` synchronously parses a string into an array of messages
|
|
69
101
|
export function parseMessages(input, options) {
|
|
70
102
|
return new MessageParser(options).parse(input);
|