n3.js-messages 0.1.4 → 0.2.0

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.
@@ -5,29 +5,42 @@ import { EventEmitter } from 'events';
5
5
  import { Parser, DataFactory } from 'n3';
6
6
  import { resolveFormat, isMessagesVersion, baseVersion, isSupportedVersion } from './formats.js';
7
7
 
8
+ /** @typedef {import('@rdfjs/types').Term} BaseTerm */
9
+ /** @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad] */
8
10
  export default class MessageParserCore {
9
11
  // `sink` receives `message(quads, index)`, `end(prefixes)`, `error(error)`
10
12
  // and optionally `quad(quad, messageIndex)`, `prefix(prefix, term)`, `version(label)`
13
+ /**
14
+ * @param {import('../common.js').MessageParserOptions<Q> | undefined} options
15
+ * @param {import('./internal.js').ParserSink<Q>} sink
16
+ */
11
17
  constructor(options, sink) {
12
18
  options = options || {};
13
19
  const format = resolveFormat(options.format);
14
20
  this._sink = sink;
15
- this._factory = options.factory || DataFactory;
21
+
22
+ /** @type {import('../common.js').MessageQuadFactory<Q>} */
23
+ this._factory = options.factory || /** @type {import('../common.js').MessageQuadFactory<Q>} */ (DataFactory);
16
24
  this._blankNodePrefix = typeof options.blankNodePrefix === 'string' ?
17
25
  options.blankNodePrefix.replace(/^_:/, '') : undefined;
18
26
  this._blankNodeCounter = 0;
19
27
  this._supportedVersions = Parser.SUPPORTED_VERSIONS;
20
28
  this._messages = options.messages === true || isMessagesVersion(options.version);
21
29
  this._index = 0;
30
+
31
+ /** @type {Q[] | null} */
22
32
  this._current = null;
33
+
34
+ /** @type {Map<string, import('@rdfjs/types').BlankNode> | null} */
23
35
  this._scope = null;
24
36
  this._seenQuad = false;
25
37
  this._failed = false;
26
38
  this._finished = false;
27
39
 
40
+ /** @type {import('n3').ParserOptions} */
28
41
  const n3Options = {
29
42
  format: format.name,
30
- factory: this._factory,
43
+ factory: /** @type {import('@rdfjs/types').DataFactory} */ (/** @type {unknown} */ (this._factory)),
31
44
  // Version labels are validated here, because N3.js does not know `-messages` labels
32
45
  parseUnsupportedVersions: true,
33
46
  // N3.js reports `MESSAGE` and `@message .` between statements through `onDirective`,
@@ -47,7 +60,7 @@ export default class MessageParserCore {
47
60
  this._line = 0;
48
61
  this._delimiterLine = 0;
49
62
  new Parser(n3Options).parse(this._input, {
50
- onQuad: (error, quad, prefixes) => this._onQuad(error, quad, prefixes),
63
+ onQuad: (error, quad, prefixes) => this._onQuad(error, /** @type {Q | null} */ (quad), prefixes),
51
64
  onPrefix: (prefix, term) => this._failed || sink.prefix && sink.prefix(prefix, term),
52
65
  onVersion: label => this._failed || this._announce(label),
53
66
  onDirective: () => this._failed || this._delimiter(),
@@ -56,6 +69,7 @@ export default class MessageParserCore {
56
69
  }
57
70
 
58
71
  // ### `write` accepts the next chunk of text
72
+ /** @param {string} text */
59
73
  write(text) {
60
74
  if (!this._failed && !this._finished && text.length > 0)
61
75
  this._input.emit('data', text);
@@ -68,6 +82,7 @@ export default class MessageParserCore {
68
82
  }
69
83
 
70
84
  // Keeps track of lines; in N-Triples and N-Quads, a delimiter must be on its own line
85
+ /** @param {{ line: number; type: string }} token */
71
86
  _onToken(token) {
72
87
  const line = token.line, delimiter = token.type === 'MESSAGE';
73
88
  if (this._lineMode && !this._failed &&
@@ -78,6 +93,9 @@ export default class MessageParserCore {
78
93
  this._line = line;
79
94
  }
80
95
 
96
+ /** @param {Error | null} error
97
+ * @param {Q | null} quad
98
+ * @param {Record<string, import('@rdfjs/types').NamedNode>} [prefixes] */
81
99
  _onQuad(error, quad, prefixes) {
82
100
  if (this._failed || this._finished)
83
101
  return;
@@ -93,6 +111,7 @@ export default class MessageParserCore {
93
111
  }
94
112
  }
95
113
 
114
+ /** @param {Q} quad */
96
115
  _addQuad(quad) {
97
116
  this._seenQuad = true;
98
117
  // Blank node labels are scoped to their message
@@ -105,6 +124,7 @@ export default class MessageParserCore {
105
124
  this._sink.quad(quad, this._index);
106
125
  }
107
126
 
127
+ /** @param {string} label */
108
128
  _announce(label) {
109
129
  const error = this._checkVersion(label);
110
130
  if (error)
@@ -119,6 +139,8 @@ export default class MessageParserCore {
119
139
  }
120
140
 
121
141
  // Validates a version label, and returns an error for unsupported ones
142
+ /** @param {string} label
143
+ * @param {boolean} [throwing] */
122
144
  _checkVersion(label, throwing) {
123
145
  if (isSupportedVersion(baseVersion(label), this._supportedVersions))
124
146
  return null;
@@ -144,6 +166,7 @@ export default class MessageParserCore {
144
166
  this._sink.message(quads, this._index++);
145
167
  }
146
168
 
169
+ /** @param {Error} error */
147
170
  _fail(error) {
148
171
  this._failed = true;
149
172
  this._current = null;
@@ -152,6 +175,8 @@ export default class MessageParserCore {
152
175
 
153
176
  // ## Blank node scoping
154
177
 
178
+ /** @param {Q} quad
179
+ * @returns {Q} */
155
180
  _scopeQuad(quad) {
156
181
  const subject = this._scopeTerm(quad.subject);
157
182
  const predicate = this._scopeTerm(quad.predicate);
@@ -162,6 +187,9 @@ export default class MessageParserCore {
162
187
  quad : this._factory.quad(subject, predicate, object, graph);
163
188
  }
164
189
 
190
+ /** @template {BaseTerm} T
191
+ * @param {T} term
192
+ * @returns {T} */
165
193
  _scopeTerm(term) {
166
194
  if (term.termType === 'BlankNode') {
167
195
  const scope = this._scope || (this._scope = new Map());
@@ -171,8 +199,9 @@ export default class MessageParserCore {
171
199
  this._factory.blankNode(`${this._blankNodePrefix}${this._blankNodeCounter++}`);
172
200
  scope.set(term.value, scoped);
173
201
  }
174
- return scoped;
202
+ return /** @type {T} */ (/** @type {unknown} */ (scoped));
175
203
  }
176
- return term.termType === 'Quad' ? this._scopeQuad(term) : term;
204
+ return term.termType === 'Quad' ? /** @type {T} */ (/** @type {unknown} */ (
205
+ this._scopeQuad(/** @type {Q} */ (/** @type {unknown} */ (term))))) : term;
177
206
  }
178
207
  }
@@ -6,10 +6,14 @@ import { Transform } from 'stream';
6
6
  import { StringDecoder } from 'string_decoder';
7
7
  import MessageParserCore from './MessageParserCore.js';
8
8
 
9
+ /** @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad] */
9
10
  export default class MessageStreamParser extends Transform {
11
+ /** @param {import('../common.js').MessageParserOptions<Q>} [options] */
10
12
  constructor(options) {
11
13
  super({ decodeStrings: false, readableObjectMode: true });
12
14
  this._decoder = new StringDecoder('utf8');
15
+
16
+ /** @type {Error | null} */
13
17
  this._error = null;
14
18
  this._core = new MessageParserCore(options, {
15
19
  message: quads => this.push(quads),
@@ -20,11 +24,15 @@ export default class MessageStreamParser extends Transform {
20
24
  });
21
25
  }
22
26
 
27
+ /** @param {string | Buffer} chunk
28
+ * @param {BufferEncoding} encoding
29
+ * @param {import('node:stream').TransformCallback} done */
23
30
  _transform(chunk, encoding, done) {
24
31
  this._core.write(typeof chunk === 'string' ? chunk : this._decoder.write(chunk));
25
32
  done(this._error);
26
33
  }
27
34
 
35
+ /** @param {import('node:stream').TransformCallback} done */
28
36
  _flush(done) {
29
37
  this._core.write(this._decoder.end());
30
38
  this._core.end();
@@ -5,19 +5,25 @@ import { Transform } from 'stream';
5
5
  import MessageWriter from './MessageWriter.js';
6
6
 
7
7
  export default class MessageStreamWriter extends Transform {
8
+ /** @param {import('../common.js').MessageWriterOptions} [options] */
8
9
  constructor(options) {
9
10
  super({ writableObjectMode: true, encoding: 'utf8' });
10
11
  // Writing into this stream never blocks, and output is pushed synchronously
12
+ /** @type {Pick<import('./internal.js').Output, 'write'>} */
11
13
  const output = { write: (chunk, encoding, done) => (this.push(chunk), done && done()) };
12
14
  this._writer = new MessageWriter(output, Object.assign({}, options, { end: false }));
13
15
  }
14
16
 
17
+ /** @param {import('../browser.js').MessageWriterInput} message
18
+ * @param {BufferEncoding} encoding
19
+ * @param {import('node:stream').TransformCallback} done */
15
20
  _transform(message, encoding, done) {
16
21
  // A message (array of quads), or a quad of a message: `{ quad, messageIndex }`
17
22
  if (Array.isArray(message)) this._writer.addMessage(message, done);
18
23
  else this._writer.addQuad(message.quad, message.messageIndex, done);
19
24
  }
20
25
 
26
+ /** @param {import('node:stream').TransformCallback} done */
21
27
  _flush(done) {
22
28
  this._writer.end(done);
23
29
  }
@@ -9,6 +9,7 @@
9
9
  import { Writer } from 'n3';
10
10
  import { resolveFormat, isMessagesVersion, baseVersion, isSupportedVersion } from './formats.js';
11
11
 
12
+ /** @extends {Writer<import('@rdfjs/types').BaseQuad>} */
12
13
  class LogWriter extends Writer {
13
14
  // ### `addDelimiter` ends the current message
14
15
  addDelimiter() {
@@ -17,11 +18,22 @@ class LogWriter extends Writer {
17
18
  }
18
19
  }
19
20
 
21
+ /** @typedef {import('./internal.js').Done} Done */
22
+ /** @typedef {import('./internal.js').End} End */
23
+ /** @typedef {import('../common.js').MessageWriterOptions} Options */
24
+ /** @typedef {Pick<import('./internal.js').Output, 'write'> & Partial<Pick<import('./internal.js').Output, 'end'>>} Output */
20
25
  export default class MessageWriter {
21
26
  // `outputStream` is optional: without it, `end` returns the output as a string
27
+ /** @overload
28
+ * @param {Options} [options] */
29
+ /** @overload
30
+ * @param {Output | null} outputStream
31
+ * @param {Options} [options] */
32
+ /** @param {Output | Options | null} [outputStream]
33
+ * @param {Options} [options] */
22
34
  constructor(outputStream, options) {
23
- if (outputStream && typeof outputStream.write !== 'function')
24
- options = outputStream, outputStream = null;
35
+ if (outputStream && typeof /** @type {Output} */ (outputStream).write !== 'function')
36
+ options = /** @type {Options} */ (outputStream), outputStream = null;
25
37
  options = options || {};
26
38
  this._format = resolveFormat(options.format);
27
39
  this._options = options;
@@ -30,24 +42,35 @@ export default class MessageWriter {
30
42
  throw new TypeError(`Unsupported RDF Messages version: "${this._version}"`);
31
43
 
32
44
  this._output = '';
33
- this._stream = outputStream;
45
+ this._stream = /** @type {Output | null | undefined} */ (outputStream);
34
46
  this._endStream = !outputStream || options.end !== false;
35
47
  this._pending = 0;
48
+
49
+ /** @type {Done[]} */
36
50
  this._waiting = [];
51
+
52
+ /** @type {Error | null} */
37
53
  this._error = null;
38
54
  this._started = false;
39
55
  this._ended = false;
40
56
  this._open = false;
41
57
  this._count = 0; // messages begun so far: the index of the next message
42
58
  this._declared = Object.assign({}, options.prefixes);
59
+
60
+ /** @type {Record<string, string>} */
43
61
  this._newPrefixes = {};
44
62
  // The N3.js writer writes to this sink, which it never ends
63
+ /** @type {Pick<Output, 'write'>} */
45
64
  this._sink = { write: (chunk, encoding, done) => this._write(chunk, done) };
65
+
66
+ /** @type {LogWriter | null} */
46
67
  this._writer = null;
47
68
  }
48
69
 
49
70
  // ### `addMessage` writes the quads of one message, followed by a delimiter.
50
71
  // The callback (or returned promise) completes once the output is flushed.
72
+ /** @param {import('@rdfjs/types').BaseQuad[]} quads
73
+ * @param {Done} [done] */
51
74
  addMessage(quads, done) {
52
75
  return this._complete(done, () => {
53
76
  if (this._open) throw new Error('A message is already open');
@@ -58,6 +81,7 @@ export default class MessageWriter {
58
81
  }
59
82
 
60
83
  // ### `beginMessage` opens a message. It is optional: the first `addQuad` opens one implicitly.
84
+ /** @param {Done} [done] */
61
85
  beginMessage(done) {
62
86
  return this._complete(done, () => {
63
87
  if (this._open) throw new Error('A message is already open');
@@ -68,6 +92,9 @@ export default class MessageWriter {
68
92
  // ### `addQuad` writes a quad into the open message right away (a message is opened if there is none).
69
93
  // With a `messageIndex` (0-based), a change of index ends the current message and writes the empty
70
94
  // messages in between, as rdf-writer-ts does; a lower index than the current one is an error.
95
+ /** @param {import('@rdfjs/types').BaseQuad} quad
96
+ * @param {number | Done} [messageIndex]
97
+ * @param {Done} [done] */
71
98
  addQuad(quad, messageIndex, done) {
72
99
  if (typeof messageIndex === 'function') done = messageIndex, messageIndex = undefined;
73
100
  return this._complete(done, () => {
@@ -78,6 +105,7 @@ export default class MessageWriter {
78
105
  }
79
106
 
80
107
  // ### `endMessage` ends the open message with a delimiter. Without an open message, it writes an empty one.
108
+ /** @param {Done} [done] */
81
109
  endMessage(done) {
82
110
  return this._complete(done, () => {
83
111
  if (!this._open) this._begin();
@@ -87,15 +115,25 @@ export default class MessageWriter {
87
115
 
88
116
  // ### `addPrefix` declares a prefix, which is written before the next message
89
117
  // and stays in effect for all messages after it
118
+ /** @param {string} prefix
119
+ * @param {string | import('@rdfjs/types').NamedNode} iri
120
+ * @param {Done} [done] */
90
121
  addPrefix(prefix, iri, done) {
91
122
  return this._complete(done, () => {
92
- if (!this._format.lineMode && this._declared[prefix] !== (iri.value || iri))
93
- this._newPrefixes[prefix] = iri.value || iri;
123
+ if (!this._format.lineMode && this._declared[prefix] !== (typeof iri === 'string' ? iri : iri.value))
124
+ this._newPrefixes[prefix] = typeof iri === 'string' ? iri : iri.value;
94
125
  });
95
126
  }
96
127
 
97
128
  // ### `end` ends the log and, unless disabled, the output stream.
98
129
  // The callback receives the output as a string if no output stream was given.
130
+ /** @overload
131
+ * @returns {Promise<string | void>} */
132
+ /** @overload
133
+ * @param {End} done
134
+ * @returns {void} */
135
+ /** @param {End} [done]
136
+ * @returns {Promise<string | void> | void} */
99
137
  end(done) {
100
138
  // Ending twice is harmless
101
139
  if (this._ended)
@@ -111,6 +149,9 @@ export default class MessageWriter {
111
149
  // ## Private methods
112
150
 
113
151
  // Runs an action and reports completion with a callback or a promise
152
+ /** @param {Done | undefined} done
153
+ * @param {() => void} action
154
+ * @returns {Promise<void> | void} */
114
155
  _complete(done, action) {
115
156
  if (this._ended)
116
157
  this._error = this._error || new Error('Cannot write after end');
@@ -119,7 +160,7 @@ export default class MessageWriter {
119
160
  action();
120
161
  }
121
162
  catch (error) {
122
- this._error = this._error || error;
163
+ this._error = this._error || /** @type {Error} */ (error);
123
164
  }
124
165
  if (typeof done === 'function')
125
166
  return this._whenFlushed(done);
@@ -127,25 +168,29 @@ export default class MessageWriter {
127
168
  }
128
169
 
129
170
  // Ends the output once all queued writes were accepted
171
+ /** @param {End} callback */
130
172
  _finish(callback) {
131
173
  this._ended = true;
132
174
  this._whenFlushed(error => this._endOutput(error, callback));
133
175
  }
134
176
 
177
+ /** @param {Error | null | undefined} error
178
+ * @param {End} callback */
135
179
  _endOutput(error, callback) {
136
180
  if (error || !this._endStream)
137
181
  return callback(error);
138
182
  if (!this._stream)
139
183
  return callback(null, this._output);
140
184
  try {
141
- this._stream.end(endError => callback(endError));
185
+ (/** @type {Required<Output>} */ (this._stream)).end(endError => callback(endError));
142
186
  }
143
187
  catch (endError) {
144
- callback(endError);
188
+ callback(/** @type {Error} */ (endError));
145
189
  }
146
190
  }
147
191
 
148
192
  // Calls back once all queued writes were accepted by the output
193
+ /** @param {Done} done */
149
194
  _whenFlushed(done) {
150
195
  if (this._pending === 0)
151
196
  this._settle(done);
@@ -153,12 +198,15 @@ export default class MessageWriter {
153
198
  this._waiting.push(done);
154
199
  }
155
200
 
201
+ /** @param {Done} done */
156
202
  _settle(done) {
157
203
  const error = this._error;
158
204
  this._error = null;
159
205
  done(error || null);
160
206
  }
161
207
 
208
+ /** @param {string} chunk
209
+ * @param {Done} [done] */
162
210
  _write(chunk, done) {
163
211
  if (!this._stream) {
164
212
  this._output += chunk;
@@ -169,11 +217,13 @@ export default class MessageWriter {
169
217
  this._stream.write(chunk, 'utf8', error => this._written(error, done));
170
218
  }
171
219
  catch (error) {
172
- this._written(error, done);
220
+ this._written(/** @type {Error} */ (error), done);
173
221
  }
174
222
  }
175
223
 
176
224
  // Registers that the output accepted a write, and wakes up those waiting for the output
225
+ /** @param {Error | null | undefined} error
226
+ * @param {Done} [done] */
177
227
  _written(error, done) {
178
228
  this._pending--;
179
229
  this._error = this._error || error || null;
@@ -202,25 +252,30 @@ export default class MessageWriter {
202
252
  // Opens a message: declares the prefixes that were added since the previous one
203
253
  _begin() {
204
254
  this._start();
205
- const writer = this._writer;
255
+ const writer = /** @type {LogWriter} */ (this._writer);
206
256
  for (const prefix of Object.keys(this._newPrefixes)) {
207
- writer.addPrefix(prefix, this._newPrefixes[prefix]);
208
- this._declared[prefix] = this._newPrefixes[prefix];
257
+ const iri = /** @type {string} */ (this._newPrefixes[prefix]);
258
+ writer.addPrefix(prefix, iri);
259
+ this._declared[prefix] = iri;
209
260
  }
210
261
  this._newPrefixes = {};
211
262
  this._open = true;
212
263
  this._count++;
213
264
  }
265
+
266
+ /** @param {import('@rdfjs/types').BaseQuad} quad */
214
267
  _add(quad) {
268
+ /** @type {Done} */
215
269
  const record = error => error && (this._error = this._error || error);
216
- this._writer.addQuad(quad.subject, quad.predicate, quad.object, quad.graph, record);
270
+ (/** @type {LogWriter} */ (this._writer)).addQuad(quad.subject, quad.predicate, quad.object, quad.graph, record);
217
271
  }
218
272
  _close() {
219
273
  this._open = false;
220
- this._writer.addDelimiter();
274
+ (/** @type {LogWriter} */ (this._writer)).addDelimiter();
221
275
  }
222
276
 
223
277
  // Makes message `index` the open message, writing empty messages for the gap
278
+ /** @param {number} index */
224
279
  _moveTo(index) {
225
280
  const current = this._count - 1;
226
281
  if (!Number.isInteger(index) || index < 0) throw new RangeError(`Invalid message index: ${index}`);
@@ -235,18 +290,25 @@ export default class MessageWriter {
235
290
  }
236
291
  }
237
292
 
293
+ /** @param {Iterable<import('@rdfjs/types').BaseQuad[]>} messages
294
+ * @param {Options} [options]
295
+ * @returns {string} */
238
296
  // ### `writeMessages` synchronously serializes an array of messages to a string
239
297
  export function writeMessages(messages, options) {
240
298
  const writer = new MessageWriter(options);
299
+
300
+ /** @type {Error[]} */
241
301
  const errors = [];
242
- let output;
302
+ let output = '';
303
+
304
+ /** @param {Error | null | undefined} error */
243
305
  function collect(error) {
244
306
  if (error)
245
307
  errors.push(error);
246
308
  }
247
309
  for (const message of messages)
248
310
  writer.addMessage(message, collect);
249
- writer.end((error, result) => (collect(error), output = result));
311
+ writer.end((error, result) => (collect(error), output = /** @type {string} */ (result)));
250
312
  if (errors.length > 0)
251
313
  throw errors[0];
252
314
  return output;
package/src/browser.js ADDED
@@ -0,0 +1,61 @@
1
+ import MessageParserCore from './MessageParserCore.js';
2
+ import MessageWriter from './MessageWriter.js';
3
+
4
+ export { default as MessageParser, parseMessages } from './MessageParser.js';
5
+ export { default as MessageWriter, writeMessages } from './MessageWriter.js';
6
+
7
+ /**
8
+ * A Web Streams parser; strings and UTF-8 bytes can be piped directly from fetch.
9
+ * @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad]
10
+ * @extends {TransformStream<import('../browser.js').MessageChunk, Q[]>}
11
+ */
12
+ export class MessageStreamParser extends TransformStream {
13
+ /** @param {import('../browser.js').BrowserParserOptions<Q>} [options] */
14
+ constructor(options = {}) {
15
+ const decoder = new TextDecoder();
16
+
17
+ /** @type {MessageParserCore<Q>} */
18
+ let core;
19
+ super({
20
+ start(controller) {
21
+ core = new MessageParserCore(options, {
22
+ message: quads => controller.enqueue(quads),
23
+ end: () => {},
24
+ error: error => { throw error; },
25
+ prefix: options.onPrefix,
26
+ version: options.onVersion,
27
+ });
28
+ },
29
+ transform(chunk) {
30
+ core.write(typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true }));
31
+ },
32
+ flush() {
33
+ core.write(decoder.decode());
34
+ core.end();
35
+ },
36
+ });
37
+ }
38
+ }
39
+
40
+ /** A Web Streams writer; accepts messages or individual indexed quads.
41
+ * @extends {TransformStream<import('../browser.js').MessageWriterInput, string>} */
42
+ export class MessageStreamWriter extends TransformStream {
43
+ /** @param {import('../common.js').MessageWriterOptions} [options] */
44
+ constructor(options) {
45
+ /** @type {MessageWriter} */
46
+ let writer;
47
+ super({
48
+ start(controller) {
49
+ /** @type {Pick<import('./internal.js').Output, 'write'>} */
50
+ const output = { write: (chunk, encoding, done) => { controller.enqueue(chunk); done(); } };
51
+ writer = new MessageWriter(output, { ...options, end: false });
52
+ },
53
+ transform(message) {
54
+ return Array.isArray(message) ? writer.addMessage(message) : writer.addQuad(message.quad, message.messageIndex);
55
+ },
56
+ flush() {
57
+ return writer.end().then(() => {});
58
+ },
59
+ });
60
+ }
61
+ }
package/src/formats.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // **formats** describes the RDF syntaxes that support RDF Messages.
2
2
 
3
+ /** @type {Record<string, { name: string; lineMode: boolean }>} */
3
4
  const FORMATS = {
4
5
  turtle: { name: 'Turtle', lineMode: false },
5
6
  trig: { name: 'TriG', lineMode: false },
@@ -12,7 +13,7 @@ const BASE_VERSIONS = ['1.2', '1.2-basic', '1.1'];
12
13
 
13
14
  // ### `resolveFormat` maps a format name or media type to a supported syntax
14
15
  export function resolveFormat(format = 'TriG') {
15
- const key = String(format).toLowerCase().split(';')[0].trim()
16
+ const key = String(format).toLowerCase().replace(/;[\s\S]*$/, '').trim()
16
17
  .replace(/^(?:text|application)\//, '')
17
18
  .replace(/^x-/, '')
18
19
  .replace(/[-_ ]/g, '');
@@ -23,16 +24,19 @@ export function resolveFormat(format = 'TriG') {
23
24
  return resolved;
24
25
  }
25
26
 
27
+ /** @param {unknown} version */
26
28
  // ### `isMessagesVersion` checks whether a version label announces RDF Messages
27
29
  export function isMessagesVersion(version) {
28
30
  return typeof version === 'string' && version.endsWith('-messages');
29
31
  }
30
32
 
33
+ /** @param {string} version */
31
34
  // ### `baseVersion` strips the `-messages` suffix of a version label
32
35
  export function baseVersion(version) {
33
36
  return isMessagesVersion(version) ? version.slice(0, -'-messages'.length) : version;
34
37
  }
35
38
 
39
+ /** @param {string} version */
36
40
  // ### `isSupportedVersion` checks whether a (base) version label is supported
37
41
  export function isSupportedVersion(version, supported = BASE_VERSIONS) {
38
42
  return supported.includes(version);
@@ -0,0 +1,15 @@
1
+ import type * as RDF from '@rdfjs/types';
2
+ export interface ParserSink<Q extends RDF.BaseQuad> {
3
+ message(quads: Q[], index: number): unknown;
4
+ end(prefixes?: Record<string, RDF.NamedNode>): unknown;
5
+ error(error: Error): unknown;
6
+ quad?(quad: Q, index: number): unknown;
7
+ prefix?(prefix: string, term: RDF.NamedNode): unknown;
8
+ version?(label: string): unknown;
9
+ }
10
+ export type Done = (error?: Error | null) => void;
11
+ export type End = (error?: Error | null, result?: string) => void;
12
+ export interface Output {
13
+ write(chunk: string, encoding: string, done: Done): unknown;
14
+ end(done: Done): unknown;
15
+ }