n3.js-messages 0.2.0 → 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/common.d.ts CHANGED
@@ -17,14 +17,14 @@ export interface MessageQuadFactory<Q extends RDF.BaseQuad = RDF.Quad>
17
17
  }
18
18
 
19
19
  export interface MessageParserOptions<Q extends RDF.BaseQuad = RDF.Quad> {
20
- /** Syntax name or media type, case-insensitive. Defaults to `TriG`. */
20
+ /** Syntax name or media type, including its optional `version` parameter. Defaults to `TriG`. */
21
21
  format?: MessageFormat;
22
22
  baseIRI?: string;
23
23
  /** Data factory used to create terms and quads. */
24
24
  factory?: MessageQuadFactory<Q>;
25
25
  /** Prefix for generated blank node labels, e.g. `b0_`. */
26
26
  blankNodePrefix?: string;
27
- /** RDF version label, e.g. `1.2-messages`; a `-messages` suffix forces message mode. */
27
+ /** RDF version label; overrides the media type parameter and in-line announcements. A `-messages` suffix forces message mode. */
28
28
  version?: string;
29
29
  /** Force message mode even without a `-messages` version declaration. */
30
30
  messages?: boolean;
@@ -45,15 +45,17 @@ export interface MessageParseCallbacks<Q extends RDF.BaseQuad = RDF.Quad> {
45
45
  }
46
46
 
47
47
  export interface MessageWriterOptions {
48
- /** Syntax name or media type, case-insensitive. Defaults to `TriG`. */
48
+ /** Syntax name or media type, including its optional `version` parameter. Defaults to `TriG`. */
49
49
  format?: MessageFormat;
50
50
  /** Prefixes that are declared up front. */
51
51
  prefixes?: { [prefix: string]: RDF.NamedNode | string };
52
52
  baseIRI?: string;
53
53
  writeBase?: boolean;
54
54
  lists?: { [listHead: string]: RDF.Term[] };
55
- /** RDF version label announced in the output. Defaults to `1.2-messages`. */
55
+ /** RDF version label; overrides the media type parameter. Defaults to `1.2-messages`. */
56
56
  version?: string;
57
+ /** Write an in-line version announcement. Defaults to `true`; set to `false` when announced externally. */
58
+ writeVersion?: boolean;
57
59
  /** Whether to end the output stream on `end()`. Defaults to `true`. */
58
60
  end?: boolean;
59
61
  }
@@ -23,6 +23,7 @@ class MessageParserCore {
23
23
  constructor(options, sink) {
24
24
  options = options || {};
25
25
  const format = (0, _formats.resolveFormat)(options.format);
26
+ this._version = options.version ?? format.version;
26
27
  this._sink = sink;
27
28
 
28
29
  /** @type {import('../common.js').MessageQuadFactory<Q>} */
@@ -30,7 +31,7 @@ class MessageParserCore {
30
31
  this._blankNodePrefix = typeof options.blankNodePrefix === 'string' ? options.blankNodePrefix.replace(/^_:/, '') : undefined;
31
32
  this._blankNodeCounter = 0;
32
33
  this._supportedVersions = _n.Parser.SUPPORTED_VERSIONS;
33
- this._messages = options.messages === true || (0, _formats.isMessagesVersion)(options.version);
34
+ this._messages = options.messages === true || (0, _formats.isMessagesVersion)(this._version);
34
35
  this._index = 0;
35
36
 
36
37
  /** @type {Q[] | null} */
@@ -53,9 +54,9 @@ class MessageParserCore {
53
54
  directives: ['message']
54
55
  };
55
56
  if (options.baseIRI) n3Options.baseIRI = options.baseIRI;
56
- if (options.version) {
57
- this._checkVersion(options.version, true);
58
- n3Options.version = (0, _formats.baseVersion)(options.version);
57
+ if (this._version !== undefined) {
58
+ this._checkVersion(this._version, true);
59
+ n3Options.version = (0, _formats.baseVersion)(this._version);
59
60
  }
60
61
  this._input = new _events.EventEmitter();
61
62
  this._lineMode = format.lineMode;
@@ -116,9 +117,11 @@ class MessageParserCore {
116
117
 
117
118
  /** @param {string} label */
118
119
  _announce(label) {
119
- const error = this._checkVersion(label);
120
+ // An externally supplied version takes precedence over in-line announcements.
121
+ const version = this._version ?? label;
122
+ const error = this._checkVersion(version);
120
123
  if (error) return this._fail(error);
121
- if ((0, _formats.isMessagesVersion)(label) && !this._messages) {
124
+ if ((0, _formats.isMessagesVersion)(version) && !this._messages) {
122
125
  if (this._seenQuad) return this._fail(new Error(`Version "${label}" must be announced before the first statement.`));
123
126
  this._messages = true;
124
127
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MessageParserCore.js","names":["resolveFormat","DataFactory","Parser","isMessagesVersion","baseVersion","EventEmitter","isSupportedVersion"],"sources":["../src/MessageParserCore.js"],"sourcesContent":["// **MessageParserCore** is the push-based engine behind all message parsers.\n// It feeds text to the N3.js parser, which recognizes the message delimiters\n// through its `directives` option, and groups the resulting quads into messages.\nimport { EventEmitter } from 'events';\nimport { Parser, DataFactory } from 'n3';\nimport { resolveFormat, isMessagesVersion, baseVersion, isSupportedVersion } from './formats.js';\n\n/** @typedef {import('@rdfjs/types').Term} BaseTerm */\n/** @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad] */\nexport default class MessageParserCore {\n // `sink` receives `message(quads, index)`, `end(prefixes)`, `error(error)`\n // and optionally `quad(quad, messageIndex)`, `prefix(prefix, term)`, `version(label)`\n /**\n * @param {import('../common.js').MessageParserOptions<Q> | undefined} options\n * @param {import('./internal.js').ParserSink<Q>} sink\n */\n constructor(options, sink) {\n options = options || {};\n const format = resolveFormat(options.format);\n this._sink = sink;\n\n /** @type {import('../common.js').MessageQuadFactory<Q>} */\n this._factory = options.factory || /** @type {import('../common.js').MessageQuadFactory<Q>} */ (DataFactory);\n this._blankNodePrefix = typeof options.blankNodePrefix === 'string' ?\n options.blankNodePrefix.replace(/^_:/, '') : undefined;\n this._blankNodeCounter = 0;\n this._supportedVersions = Parser.SUPPORTED_VERSIONS;\n this._messages = options.messages === true || isMessagesVersion(options.version);\n this._index = 0;\n\n /** @type {Q[] | null} */\n this._current = null;\n\n /** @type {Map<string, import('@rdfjs/types').BlankNode> | null} */\n this._scope = null;\n this._seenQuad = false;\n this._failed = false;\n this._finished = false;\n\n /** @type {import('n3').ParserOptions} */\n const n3Options = {\n format: format.name,\n factory: /** @type {import('@rdfjs/types').DataFactory} */ (/** @type {unknown} */ (this._factory)),\n // Version labels are validated here, because N3.js does not know `-messages` labels\n parseUnsupportedVersions: true,\n // N3.js reports `MESSAGE` and `@message .` between statements through `onDirective`,\n // in order with the quads, and rejects them anywhere else\n directives: ['message'],\n };\n if (options.baseIRI)\n n3Options.baseIRI = options.baseIRI;\n if (options.version) {\n this._checkVersion(options.version, true);\n n3Options.version = baseVersion(options.version);\n }\n\n this._input = new EventEmitter();\n this._lineMode = format.lineMode;\n // The line of the current token, and of the last delimiter\n this._line = 0;\n this._delimiterLine = 0;\n new Parser(n3Options).parse(this._input, {\n onQuad: (error, quad, prefixes) => this._onQuad(error, /** @type {Q | null} */ (quad), prefixes),\n onPrefix: (prefix, term) => this._failed || sink.prefix && sink.prefix(prefix, term),\n onVersion: label => this._failed || this._announce(label),\n onDirective: () => this._failed || this._delimiter(),\n onToken: token => this._onToken(token),\n });\n }\n\n // ### `write` accepts the next chunk of text\n /** @param {string} text */\n write(text) {\n if (!this._failed && !this._finished && text.length > 0)\n this._input.emit('data', text);\n }\n\n // ### `end` signals the end of the input\n end() {\n if (!this._failed && !this._finished)\n this._input.emit('end');\n }\n\n // Keeps track of lines; in N-Triples and N-Quads, a delimiter must be on its own line\n /** @param {{ line: number; type: string }} token */\n _onToken(token) {\n const line = token.line, delimiter = token.type === 'MESSAGE';\n if (this._lineMode && !this._failed &&\n (delimiter ? line === this._line : line === this._delimiterLine && token.type !== 'eof'))\n this._fail(new Error(`Unexpected \"MESSAGE\" on line ${line}.`));\n if (delimiter)\n this._delimiterLine = line;\n this._line = line;\n }\n\n /** @param {Error | null} error\n * @param {Q | null} quad\n * @param {Record<string, import('@rdfjs/types').NamedNode>} [prefixes] */\n _onQuad(error, quad, prefixes) {\n if (this._failed || this._finished)\n return;\n if (error)\n this._fail(error);\n else if (quad)\n this._addQuad(quad);\n else {\n this._finished = true;\n if (this._current !== null)\n this._emitMessage();\n this._sink.end(prefixes);\n }\n }\n\n /** @param {Q} quad */\n _addQuad(quad) {\n this._seenQuad = true;\n // Blank node labels are scoped to their message\n if (this._messages)\n quad = this._scopeQuad(quad);\n if (this._current === null)\n this._current = [];\n this._current.push(quad);\n if (this._sink.quad)\n this._sink.quad(quad, this._index);\n }\n\n /** @param {string} label */\n _announce(label) {\n const error = this._checkVersion(label);\n if (error)\n return this._fail(error);\n if (isMessagesVersion(label) && !this._messages) {\n if (this._seenQuad)\n return this._fail(new Error(`Version \"${label}\" must be announced before the first statement.`));\n this._messages = true;\n }\n if (this._sink.version)\n this._sink.version(label);\n }\n\n // Validates a version label, and returns an error for unsupported ones\n /** @param {string} label\n * @param {boolean} [throwing] */\n _checkVersion(label, throwing) {\n if (isSupportedVersion(baseVersion(label), this._supportedVersions))\n return null;\n const error = new Error(`Detected unsupported version: \"${label}\"`);\n if (throwing)\n throw error;\n return error;\n }\n\n _delimiter() {\n if (!this._messages) {\n return this._fail(new Error(`Unexpected \"MESSAGE\" on line ${this._line}: the document did not announce ` +\n 'a version with the \"-messages\" suffix.'));\n }\n this._emitMessage();\n }\n\n // Finalizes the current message, which is empty if no quad was seen\n _emitMessage() {\n const quads = this._current || [];\n this._current = null;\n this._scope = null;\n this._sink.message(quads, this._index++);\n }\n\n /** @param {Error} error */\n _fail(error) {\n this._failed = true;\n this._current = null;\n this._sink.error(error);\n }\n\n // ## Blank node scoping\n\n /** @param {Q} quad\n * @returns {Q} */\n _scopeQuad(quad) {\n const subject = this._scopeTerm(quad.subject);\n const predicate = this._scopeTerm(quad.predicate);\n const object = this._scopeTerm(quad.object);\n const graph = this._scopeTerm(quad.graph);\n return subject === quad.subject && predicate === quad.predicate &&\n object === quad.object && graph === quad.graph ?\n quad : this._factory.quad(subject, predicate, object, graph);\n }\n\n /** @template {BaseTerm} T\n * @param {T} term\n * @returns {T} */\n _scopeTerm(term) {\n if (term.termType === 'BlankNode') {\n const scope = this._scope || (this._scope = new Map());\n let scoped = scope.get(term.value);\n if (!scoped) {\n scoped = this._blankNodePrefix === undefined ? this._factory.blankNode() :\n this._factory.blankNode(`${this._blankNodePrefix}${this._blankNodeCounter++}`);\n scope.set(term.value, scoped);\n }\n return /** @type {T} */ (/** @type {unknown} */ (scoped));\n }\n return term.termType === 'Quad' ? /** @type {T} */ (/** @type {unknown} */ (\n this._scopeQuad(/** @type {Q} */ (/** @type {unknown} */ (term))))) : term;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"MessageParserCore.js","names":["resolveFormat","DataFactory","Parser","isMessagesVersion","baseVersion","EventEmitter","isSupportedVersion"],"sources":["../src/MessageParserCore.js"],"sourcesContent":["// **MessageParserCore** is the push-based engine behind all message parsers.\n// It feeds text to the N3.js parser, which recognizes the message delimiters\n// through its `directives` option, and groups the resulting quads into messages.\nimport { EventEmitter } from 'events';\nimport { Parser, DataFactory } from 'n3';\nimport { resolveFormat, isMessagesVersion, baseVersion, isSupportedVersion } from './formats.js';\n\n/** @typedef {import('@rdfjs/types').Term} BaseTerm */\n/** @template {import('@rdfjs/types').BaseQuad} [Q=import('@rdfjs/types').Quad] */\nexport default class MessageParserCore {\n // `sink` receives `message(quads, index)`, `end(prefixes)`, `error(error)`\n // and optionally `quad(quad, messageIndex)`, `prefix(prefix, term)`, `version(label)`\n /**\n * @param {import('../common.js').MessageParserOptions<Q> | undefined} options\n * @param {import('./internal.js').ParserSink<Q>} sink\n */\n constructor(options, sink) {\n options = options || {};\n const format = resolveFormat(options.format);\n this._version = options.version ?? format.version;\n this._sink = sink;\n\n /** @type {import('../common.js').MessageQuadFactory<Q>} */\n this._factory = options.factory || /** @type {import('../common.js').MessageQuadFactory<Q>} */ (DataFactory);\n this._blankNodePrefix = typeof options.blankNodePrefix === 'string' ?\n options.blankNodePrefix.replace(/^_:/, '') : undefined;\n this._blankNodeCounter = 0;\n this._supportedVersions = Parser.SUPPORTED_VERSIONS;\n this._messages = options.messages === true || isMessagesVersion(this._version);\n this._index = 0;\n\n /** @type {Q[] | null} */\n this._current = null;\n\n /** @type {Map<string, import('@rdfjs/types').BlankNode> | null} */\n this._scope = null;\n this._seenQuad = false;\n this._failed = false;\n this._finished = false;\n\n /** @type {import('n3').ParserOptions} */\n const n3Options = {\n format: format.name,\n factory: /** @type {import('@rdfjs/types').DataFactory} */ (/** @type {unknown} */ (this._factory)),\n // Version labels are validated here, because N3.js does not know `-messages` labels\n parseUnsupportedVersions: true,\n // N3.js reports `MESSAGE` and `@message .` between statements through `onDirective`,\n // in order with the quads, and rejects them anywhere else\n directives: ['message'],\n };\n if (options.baseIRI)\n n3Options.baseIRI = options.baseIRI;\n if (this._version !== undefined) {\n this._checkVersion(this._version, true);\n n3Options.version = baseVersion(this._version);\n }\n\n this._input = new EventEmitter();\n this._lineMode = format.lineMode;\n // The line of the current token, and of the last delimiter\n this._line = 0;\n this._delimiterLine = 0;\n new Parser(n3Options).parse(this._input, {\n onQuad: (error, quad, prefixes) => this._onQuad(error, /** @type {Q | null} */ (quad), prefixes),\n onPrefix: (prefix, term) => this._failed || sink.prefix && sink.prefix(prefix, term),\n onVersion: label => this._failed || this._announce(label),\n onDirective: () => this._failed || this._delimiter(),\n onToken: token => this._onToken(token),\n });\n }\n\n // ### `write` accepts the next chunk of text\n /** @param {string} text */\n write(text) {\n if (!this._failed && !this._finished && text.length > 0)\n this._input.emit('data', text);\n }\n\n // ### `end` signals the end of the input\n end() {\n if (!this._failed && !this._finished)\n this._input.emit('end');\n }\n\n // Keeps track of lines; in N-Triples and N-Quads, a delimiter must be on its own line\n /** @param {{ line: number; type: string }} token */\n _onToken(token) {\n const line = token.line, delimiter = token.type === 'MESSAGE';\n if (this._lineMode && !this._failed &&\n (delimiter ? line === this._line : line === this._delimiterLine && token.type !== 'eof'))\n this._fail(new Error(`Unexpected \"MESSAGE\" on line ${line}.`));\n if (delimiter)\n this._delimiterLine = line;\n this._line = line;\n }\n\n /** @param {Error | null} error\n * @param {Q | null} quad\n * @param {Record<string, import('@rdfjs/types').NamedNode>} [prefixes] */\n _onQuad(error, quad, prefixes) {\n if (this._failed || this._finished)\n return;\n if (error)\n this._fail(error);\n else if (quad)\n this._addQuad(quad);\n else {\n this._finished = true;\n if (this._current !== null)\n this._emitMessage();\n this._sink.end(prefixes);\n }\n }\n\n /** @param {Q} quad */\n _addQuad(quad) {\n this._seenQuad = true;\n // Blank node labels are scoped to their message\n if (this._messages)\n quad = this._scopeQuad(quad);\n if (this._current === null)\n this._current = [];\n this._current.push(quad);\n if (this._sink.quad)\n this._sink.quad(quad, this._index);\n }\n\n /** @param {string} label */\n _announce(label) {\n // An externally supplied version takes precedence over in-line announcements.\n const version = this._version ?? label;\n const error = this._checkVersion(version);\n if (error)\n return this._fail(error);\n if (isMessagesVersion(version) && !this._messages) {\n if (this._seenQuad)\n return this._fail(new Error(`Version \"${label}\" must be announced before the first statement.`));\n this._messages = true;\n }\n if (this._sink.version)\n this._sink.version(label);\n }\n\n // Validates a version label, and returns an error for unsupported ones\n /** @param {string} label\n * @param {boolean} [throwing] */\n _checkVersion(label, throwing) {\n if (isSupportedVersion(baseVersion(label), this._supportedVersions))\n return null;\n const error = new Error(`Detected unsupported version: \"${label}\"`);\n if (throwing)\n throw error;\n return error;\n }\n\n _delimiter() {\n if (!this._messages) {\n return this._fail(new Error(`Unexpected \"MESSAGE\" on line ${this._line}: the document did not announce ` +\n 'a version with the \"-messages\" suffix.'));\n }\n this._emitMessage();\n }\n\n // Finalizes the current message, which is empty if no quad was seen\n _emitMessage() {\n const quads = this._current || [];\n this._current = null;\n this._scope = null;\n this._sink.message(quads, this._index++);\n }\n\n /** @param {Error} error */\n _fail(error) {\n this._failed = true;\n this._current = null;\n this._sink.error(error);\n }\n\n // ## Blank node scoping\n\n /** @param {Q} quad\n * @returns {Q} */\n _scopeQuad(quad) {\n const subject = this._scopeTerm(quad.subject);\n const predicate = this._scopeTerm(quad.predicate);\n const object = this._scopeTerm(quad.object);\n const graph = this._scopeTerm(quad.graph);\n return subject === quad.subject && predicate === quad.predicate &&\n object === quad.object && graph === quad.graph ?\n quad : this._factory.quad(subject, predicate, object, graph);\n }\n\n /** @template {BaseTerm} T\n * @param {T} term\n * @returns {T} */\n _scopeTerm(term) {\n if (term.termType === 'BlankNode') {\n const scope = this._scope || (this._scope = new Map());\n let scoped = scope.get(term.value);\n if (!scoped) {\n scoped = this._blankNodePrefix === undefined ? this._factory.blankNode() :\n this._factory.blankNode(`${this._blankNodePrefix}${this._blankNodeCounter++}`);\n scope.set(term.value, scoped);\n }\n return /** @type {T} */ (/** @type {unknown} */ (scoped));\n }\n return term.termType === 'Quad' ? /** @type {T} */ (/** @type {unknown} */ (\n this._scopeQuad(/** @type {Q} */ (/** @type {unknown} */ (term))))) : term;\n }\n}\n"],"mappings":";;;;;;AAGA;AACA;AACA;AALA;AACA;AACA;;AAKA;AACA;AACe,MAAM,iBAAiB,CAAC;EACrC;EACA;EACA;AACF;AACA;AACA;EACE,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE;IACzB,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,IAAAA,SAAA,aAAa,EAAC,OAAO,CAAC,MAAM,CAAC;IAC5C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI;;IAEjB;IACA,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,IAAI,2DAA6DC,GAAA,WAAY;IAC5G,IAAI,CAAC,gBAAgB,GAAG,OAAO,OAAO,CAAC,eAAe,KAAK,QAAQ,GACjE,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,SAAS;IACxD,IAAI,CAAC,iBAAiB,GAAG,CAAC;IAC1B,IAAI,CAAC,kBAAkB,GAAGC,GAAA,MAAM,CAAC,kBAAkB;IACnD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAAC,SAAA,iBAAiB,EAAC,IAAI,CAAC,QAAQ,CAAC;IAC9E,IAAI,CAAC,MAAM,GAAG,CAAC;;IAEf;IACA,IAAI,CAAC,QAAQ,GAAG,IAAI;;IAEpB;IACA,IAAI,CAAC,MAAM,GAAG,IAAI;IAClB,IAAI,CAAC,SAAS,GAAG,KAAK;IACtB,IAAI,CAAC,OAAO,GAAG,KAAK;IACpB,IAAI,CAAC,SAAS,GAAG,KAAK;;IAEtB;IACA,MAAM,SAAS,GAAG;MAChB,MAAM,EAAE,MAAM,CAAC,IAAI;MACnB,OAAO,GAAE,kDAAmD,sBAAwB,IAAI,CAAC,QAAQ,CAAE;MACnG;MACA,wBAAwB,EAAE,IAAI;MAC9B;MACA;MACA,UAAU,EAAE,CAAC,SAAS;IACxB,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,EACjB,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO;IACrC,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE;MAC/B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;MACvC,SAAS,CAAC,OAAO,GAAG,IAAAC,SAAA,WAAW,EAAC,IAAI,CAAC,QAAQ,CAAC;IAChD;IAEA,IAAI,CAAC,MAAM,GAAG,IAAIC,QAAA,YAAY,CAAC,CAAC;IAChC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,QAAQ;IAChC;IACA,IAAI,CAAC,KAAK,GAAG,CAAC;IACd,IAAI,CAAC,cAAc,GAAG,CAAC;IACvB,IAAIH,GAAA,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;MACvC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,uBAAyB,IAAI,EAAG,QAAQ,CAAC;MAChG,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC;MACpF,SAAS,EAAE,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;MACzD,WAAW,EAAE,MAAM,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;MACpD,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK;IACvC,CAAC,CAAC;EACJ;;EAEA;EACA;EACA,KAAK,CAAC,IAAI,EAAE;IACV,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EACrD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;EAClC;;EAEA;EACA,GAAG,GAAG;IACJ,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAClC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;EAC3B;;EAEA;EACA;EACA,QAAQ,CAAC,KAAK,EAAE;IACd,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI;MAAE,SAAS,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS;IAC7D,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,KAC9B,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,EAC1F,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,GAAG,CAAC,CAAC;IAChE,IAAI,SAAS,EACX,IAAI,CAAC,cAAc,GAAG,IAAI;IAC5B,IAAI,CAAC,KAAK,GAAG,IAAI;EACnB;;EAEA;AACF;AACA;EACE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC7B,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,EAChC;IACF,IAAI,KAAK,EACP,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KACf,IAAI,IAAI,EACX,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KACjB;MACH,IAAI,CAAC,SAAS,GAAG,IAAI;MACrB,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EACxB,IAAI,CAAC,YAAY,CAAC,CAAC;MACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC1B;EACF;;EAEA;EACA,QAAQ,CAAC,IAAI,EAAE;IACb,IAAI,CAAC,SAAS,GAAG,IAAI;IACrB;IACA,IAAI,IAAI,CAAC,SAAS,EAChB,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;IAC9B,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EACxB,IAAI,CAAC,QAAQ,GAAG,EAAE;IACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EACjB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;EACtC;;EAEA;EACA,SAAS,CAAC,KAAK,EAAE;IACf;IACA,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;IACzC,IAAI,KAAK,EACP,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B,IAAI,IAAAC,SAAA,iBAAiB,EAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;MACjD,IAAI,IAAI,CAAC,SAAS,EAChB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,YAAY,KAAK,iDAAiD,CAAC,CAAC;MAClG,IAAI,CAAC,SAAS,GAAG,IAAI;IACvB;IACA,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;EAC7B;;EAEA;EACA;AACF;EACE,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE;IAC7B,IAAI,IAAAG,SAAA,kBAAkB,EAAC,IAAAF,SAAA,WAAW,EAAC,KAAK,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC,EACjE,OAAO,IAAI;IACb,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,kCAAkC,KAAK,GAAG,CAAC;IACnE,IAAI,QAAQ,EACV,MAAM,KAAK;IACb,OAAO,KAAK;EACd;EAEA,UAAU,GAAG;IACX,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;MACnB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,KAAK,kCAAkC,GAC5E,wCAAwC,CAAC,CAAC;IACxE;IACA,IAAI,CAAC,YAAY,CAAC,CAAC;EACrB;;EAEA;EACA,YAAY,GAAG;IACb,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE;IACjC,IAAI,CAAC,QAAQ,GAAG,IAAI;IACpB,IAAI,CAAC,MAAM,GAAG,IAAI;IAClB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;EAC1C;;EAEA;EACA,KAAK,CAAC,KAAK,EAAE;IACX,IAAI,CAAC,OAAO,GAAG,IAAI;IACnB,IAAI,CAAC,QAAQ,GAAG,IAAI;IACpB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;EACzB;;EAEA;;EAEA;AACF;EACE,UAAU,CAAC,IAAI,EAAE;IACf,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;IACzC,OAAO,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,SAAS,KAAK,IAAI,CAAC,SAAS,IACxD,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK,GACnD,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC;EAChE;;EAEA;AACF;AACA;EACE,UAAU,CAAC,IAAI,EAAE;IACf,IAAI,IAAI,CAAC,QAAQ,KAAK,WAAW,EAAE;MACjC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;MACtD,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;MAClC,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,GAAG,IAAI,CAAC,gBAAgB,KAAK,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GACtE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAChF,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;MAC/B;MACA,OAAO,iBAAkB,sBAAwB,MAAM;IACzD;IACA,OAAO,IAAI,CAAC,QAAQ,KAAK,MAAM,IAAG,iBAAkB;IAClD,IAAI,CAAC,UAAU,CAAC,iBAAkB,sBAAwB,IAAM,CAAC,IAAK,IAAI;EAC9E;AACF;AAAC","ignoreList":[]}
@@ -43,7 +43,7 @@ class MessageWriter {
43
43
  options = options || {};
44
44
  this._format = (0, _formats.resolveFormat)(options.format);
45
45
  this._options = options;
46
- this._version = options.version === undefined ? '1.2-messages' : options.version;
46
+ this._version = options.version ?? this._format.version ?? '1.2-messages';
47
47
  if (!(0, _formats.isMessagesVersion)(this._version) || !(0, _formats.isSupportedVersion)((0, _formats.baseVersion)(this._version))) throw new TypeError(`Unsupported RDF Messages version: "${this._version}"`);
48
48
  this._output = '';
49
49
  this._stream = /** @type {Output | null | undefined} */outputStream;
@@ -229,7 +229,7 @@ class MessageWriter {
229
229
  this._writer = new LogWriter(this._sink, {
230
230
  format: this._format.name,
231
231
  end: false,
232
- version: this._version,
232
+ version: options.writeVersion === false ? undefined : this._version,
233
233
  baseIRI: options.baseIRI,
234
234
  writeBase: options.writeBase,
235
235
  prefixes: this._declared
@@ -1 +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 === undefined ? '1.2-messages' : options.version;\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: 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":[]}
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":";;;;;;;AAQA;AACA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA,MAAM,SAAS,SAASA,GAAA,MAAM,CAAC;EAC7B;EACA,YAAY,GAAG;IACb,IAAI,CAAC,aAAa,CAAC,CAAC;IACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,GAAG,WAAW,GAAG,cAAc,CAAC;EAC5D;AACF;;AAEA;AACA;AACA;AACA;AACe,MAAM,aAAa,CAAC;EACjC;EACA;AACF;EACE;AACF;AACA;EACE;AACF;EACE,WAAW,CAAC,YAAY,EAAE,OAAO,EAAE;IACjC,IAAI,YAAY,IAAI,OAAO,qBAAuB,YAAY,CAAE,KAAK,KAAK,UAAU,EAClF,OAAO,GAAG,sBAAwB,YAAa,EAAE,YAAY,GAAG,IAAI;IACtE,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC;IACvB,IAAI,CAAC,OAAO,GAAG,IAAAC,SAAA,aAAa,EAAC,OAAO,CAAC,MAAM,CAAC;IAC5C,IAAI,CAAC,QAAQ,GAAG,OAAO;IACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,cAAc;IACzE,IAAI,CAAC,IAAAC,SAAA,iBAAiB,EAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAAC,SAAA,kBAAkB,EAAC,IAAAC,SAAA,WAAW,EAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EACtF,MAAM,IAAI,SAAS,CAAC,sCAAsC,IAAI,CAAC,QAAQ,GAAG,CAAC;IAE7E,IAAI,CAAC,OAAO,GAAG,EAAE;IACjB,IAAI,CAAC,OAAO,GAAG,wCAA0C,YAAa;IACtE,IAAI,CAAC,UAAU,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK;IACxD,IAAI,CAAC,QAAQ,GAAG,CAAC;;IAEjB;IACA,IAAI,CAAC,QAAQ,GAAG,EAAE;;IAElB;IACA,IAAI,CAAC,MAAM,GAAG,IAAI;IAClB,IAAI,CAAC,QAAQ,GAAG,KAAK;IACrB,IAAI,CAAC,MAAM,GAAG,KAAK;IACnB,IAAI,CAAC,KAAK,GAAG,KAAK;IAClB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACjB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC;;IAEpD;IACA,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;IACtB;IACA;IACA,IAAI,CAAC,KAAK,GAAG;MAAE,KAAK,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI;IAAE,CAAC;;IAE3E;IACA,IAAI,CAAC,OAAO,GAAG,IAAI;EACrB;;EAEA;EACA;EACA;AACF;EACE,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE;IACtB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM;MAChC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC;MAC5D,IAAI,CAAC,MAAM,CAAC,CAAC;MACb,KAAK,MAAM,IAAI,IAAI,KAAK,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;MAC/C,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC,CAAC;EACJ;;EAEA;EACA;EACA,YAAY,CAAC,IAAI,EAAE;IACjB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM;MAChC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC;MAC5D,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC,CAAC;EACJ;;EAEA;EACA;EACA;EACA;AACF;AACA;EACE,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;IAChC,IAAI,OAAO,YAAY,KAAK,UAAU,EAAE,IAAI,GAAG,YAAY,EAAE,YAAY,GAAG,SAAS;IACrF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM;MAChC,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,KAC/E,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;MACnC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACjB,CAAC,CAAC;EACJ;;EAEA;EACA;EACA,UAAU,CAAC,IAAI,EAAE;IACf,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM;MAChC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;MAC9B,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC,CAAC;EACJ;;EAEA;EACA;EACA;AACF;AACA;EACE,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE;IAC3B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM;MAChC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,QAAQ,GAAG,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,EAClG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,OAAO,GAAG,KAAK,QAAQ,GAAG,GAAG,GAAG,GAAG,CAAC,KAAK;IACzE,CAAC,CAAC;EACJ;;EAEA;EACA;EACA;AACF;EACE;AACF;AACA;EACE;AACF;EACE,GAAG,CAAC,IAAI,EAAE;IACR;IACA,IAAI,IAAI,CAAC,MAAM,EACb,OAAO,OAAO,IAAI,KAAK,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,CAAC,CAAC;IACb,IAAI,IAAI,CAAC,KAAK,EACZ,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,IAAI,OAAO,IAAI,KAAK,UAAU,EAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;EACnH;;EAEA;;EAEA;EACA;AACF;AACA;EACE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE;IACtB,IAAI,IAAI,CAAC,MAAM,EACb,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,KAEjE,IAAI;MACF,MAAM,CAAC,CAAC;IACV,CAAC,CACD,OAAO,KAAK,EAAE;MACZ,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,KAAI,oBAAsB,KAAK,CAAC;IAC3D;IACF,IAAI,OAAO,IAAI,KAAK,UAAU,EAC5B,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;IAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;EACxG;;EAEA;EACA;EACA,OAAO,CAAC,QAAQ,EAAE;IAChB,IAAI,CAAC,MAAM,GAAG,IAAI;IAClB,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;EAC9D;;EAEA;AACF;EACE,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE;IAC1B,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,UAAU,EAC3B,OAAO,QAAQ,CAAC,KAAK,CAAC;IACxB,IAAI,CAAC,IAAI,CAAC,OAAO,EACf,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC;IACrC,IAAI;MACF,CAAC,+BAAiC,IAAI,CAAC,OAAO,EAAG,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtF,CAAC,CACD,OAAO,QAAQ,EAAE;MACf,QAAQ,CAAC,oBAAsB,QAAS,CAAC;IAC3C;EACF;;EAEA;EACA;EACA,YAAY,CAAC,IAAI,EAAE;IACjB,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAEnB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;EAC5B;;EAEA;EACA,OAAO,CAAC,IAAI,EAAE;IACZ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;IACzB,IAAI,CAAC,MAAM,GAAG,IAAI;IAClB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;EACrB;;EAEA;AACF;EACE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE;IAClB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;MACjB,IAAI,CAAC,OAAO,IAAI,KAAK;MACrB,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC;IACvB;IACA,IAAI,CAAC,QAAQ,EAAE;IACf,IAAI;MACF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC,CACD,OAAO,KAAK,EAAE;MACZ,IAAI,CAAC,QAAQ,CAAC,oBAAsB,KAAK,EAAG,IAAI,CAAC;IACnD;EACF;;EAEA;EACA;AACF;EACE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE;IACpB,IAAI,CAAC,QAAQ,EAAE;IACf,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI;IAC1C,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC;IACnB,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;EACvE;;EAEA;EACA;EACA,MAAM,GAAG;IACP,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;MAClB,IAAI,CAAC,QAAQ,GAAG,IAAI;MACpB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;MAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE;QACvC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;QACzB,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,OAAO,CAAC,YAAY,KAAK,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,QAAQ;QACnE,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,IAAI,CAAC;MACjB,CAAC,CAAC;IACJ;EACF;;EAEA;EACA,MAAM,GAAG;IACP,IAAI,CAAC,MAAM,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,wBAA0B,IAAI,CAAC,OAAQ;IACtD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE;MACnD,MAAM,GAAG,GAAG,qBAAuB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAE;MAC7D,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;MAC7B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,GAAG;IAC9B;IACA,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,GAAG,IAAI;IACjB,IAAI,CAAC,MAAM,EAAE;EACf;;EAEA;EACA,IAAI,CAAC,IAAI,EAAE;IACT;IACA,MAAM,MAAM,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;IACrE,CAAC,wBAA0B,IAAI,CAAC,OAAO,EAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;EAClH;EACA,MAAM,GAAG;IACP,IAAI,CAAC,KAAK,GAAG,KAAK;IAClB,CAAC,wBAA0B,IAAI,CAAC,OAAO,EAAG,YAAY,CAAC,CAAC;EAC1D;;EAEA;EACA;EACA,OAAO,CAAC,KAAK,EAAE;IACb,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,MAAM,IAAI,UAAU,CAAC,0BAA0B,KAAK,EAAE,CAAC;IAClG,IAAI,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE;IACrC,IAAI,KAAK,IAAI,OAAO,EAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,KAAK,4CAA4C,OAAO,EAAE,CAAC;IACvH,IAAI,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE;MAC1B,IAAI,CAAC,MAAM,CAAC,CAAC;MACb,IAAI,CAAC,MAAM,CAAC,CAAC;IACf;IACA,IAAI,CAAC,MAAM,CAAC,CAAC;EACf;AACF;;AAEA;AACA;AACA;AACA;AAAA;AACO,SAAS,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE;EAC/C,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC;;EAEzC;EACA,MAAM,MAAM,GAAG,EAAE;EACjB,IAAI,MAAM,GAAG,EAAE;;EAEf;EACA,SAAS,OAAO,CAAC,KAAK,EAAE;IACtB,IAAI,KAAK,EACP,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;EACtB;EACA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAC5B,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC;EACrC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,qBAAuB,MAAO,CAAC,CAAC;EACxF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EACnB,MAAM,MAAM,CAAC,CAAC,CAAC;EACjB,OAAO,MAAM;AACf","ignoreList":[]}
package/lib/formats.js CHANGED
@@ -33,11 +33,24 @@ const FORMATS = {
33
33
  const BASE_VERSIONS = ['1.2', '1.2-basic', '1.1'];
34
34
 
35
35
  // ### `resolveFormat` maps a format name or media type to a supported syntax
36
+ /** @returns {{ name: string; lineMode: boolean; version?: string }} */
36
37
  function resolveFormat(format = 'TriG') {
37
38
  const key = String(format).toLowerCase().replace(/;[\s\S]*$/, '').trim().replace(/^(?:text|application)\//, '').replace(/^x-/, '').replace(/[-_ ]/g, '');
38
39
  const resolved = FORMATS[key];
39
40
  if (!resolved) throw new TypeError(`Unsupported RDF Messages format: "${format}". ` + 'Supported formats are Turtle, TriG, N-Triples and N-Quads.');
40
- return resolved;
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
+ };
41
54
  }
42
55
 
43
56
  /** @param {unknown} version */
@@ -1 +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\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 return resolved;\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;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,OAAO,QAAQ;AACjB;;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":[]}
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3.js-messages",
3
- "version": "0.2.0",
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",
@@ -17,6 +17,7 @@ export default class MessageParserCore {
17
17
  constructor(options, sink) {
18
18
  options = options || {};
19
19
  const format = resolveFormat(options.format);
20
+ this._version = options.version ?? format.version;
20
21
  this._sink = sink;
21
22
 
22
23
  /** @type {import('../common.js').MessageQuadFactory<Q>} */
@@ -25,7 +26,7 @@ export default class MessageParserCore {
25
26
  options.blankNodePrefix.replace(/^_:/, '') : undefined;
26
27
  this._blankNodeCounter = 0;
27
28
  this._supportedVersions = Parser.SUPPORTED_VERSIONS;
28
- this._messages = options.messages === true || isMessagesVersion(options.version);
29
+ this._messages = options.messages === true || isMessagesVersion(this._version);
29
30
  this._index = 0;
30
31
 
31
32
  /** @type {Q[] | null} */
@@ -49,9 +50,9 @@ export default class MessageParserCore {
49
50
  };
50
51
  if (options.baseIRI)
51
52
  n3Options.baseIRI = options.baseIRI;
52
- if (options.version) {
53
- this._checkVersion(options.version, true);
54
- n3Options.version = baseVersion(options.version);
53
+ if (this._version !== undefined) {
54
+ this._checkVersion(this._version, true);
55
+ n3Options.version = baseVersion(this._version);
55
56
  }
56
57
 
57
58
  this._input = new EventEmitter();
@@ -126,10 +127,12 @@ export default class MessageParserCore {
126
127
 
127
128
  /** @param {string} label */
128
129
  _announce(label) {
129
- const error = this._checkVersion(label);
130
+ // An externally supplied version takes precedence over in-line announcements.
131
+ const version = this._version ?? label;
132
+ const error = this._checkVersion(version);
130
133
  if (error)
131
134
  return this._fail(error);
132
- if (isMessagesVersion(label) && !this._messages) {
135
+ if (isMessagesVersion(version) && !this._messages) {
133
136
  if (this._seenQuad)
134
137
  return this._fail(new Error(`Version "${label}" must be announced before the first statement.`));
135
138
  this._messages = true;
@@ -37,7 +37,7 @@ export default class MessageWriter {
37
37
  options = options || {};
38
38
  this._format = resolveFormat(options.format);
39
39
  this._options = options;
40
- this._version = options.version === undefined ? '1.2-messages' : options.version;
40
+ this._version = options.version ?? this._format.version ?? '1.2-messages';
41
41
  if (!isMessagesVersion(this._version) || !isSupportedVersion(baseVersion(this._version)))
42
42
  throw new TypeError(`Unsupported RDF Messages version: "${this._version}"`);
43
43
 
@@ -241,7 +241,7 @@ export default class MessageWriter {
241
241
  this._writer = new LogWriter(this._sink, {
242
242
  format: this._format.name,
243
243
  end: false,
244
- version: this._version,
244
+ version: options.writeVersion === false ? undefined : this._version,
245
245
  baseIRI: options.baseIRI,
246
246
  writeBase: options.writeBase,
247
247
  prefixes: this._declared,
package/src/formats.js CHANGED
@@ -12,6 +12,7 @@ const FORMATS = {
12
12
  const BASE_VERSIONS = ['1.2', '1.2-basic', '1.1'];
13
13
 
14
14
  // ### `resolveFormat` maps a format name or media type to a supported syntax
15
+ /** @returns {{ name: string; lineMode: boolean; version?: string }} */
15
16
  export function resolveFormat(format = 'TriG') {
16
17
  const key = String(format).toLowerCase().replace(/;[\s\S]*$/, '').trim()
17
18
  .replace(/^(?:text|application)\//, '')
@@ -21,7 +22,17 @@ export function resolveFormat(format = 'TriG') {
21
22
  if (!resolved)
22
23
  throw new TypeError(`Unsupported RDF Messages format: "${format}". ` +
23
24
  'Supported formats are Turtle, TriG, N-Triples and N-Quads.');
24
- return resolved;
25
+ let version;
26
+ // Consume quoted values whole, so a semicolon inside another parameter cannot
27
+ // accidentally introduce a version parameter. Parameter names are case-insensitive.
28
+ for (const parameter of String(format).matchAll(/;\s*([^;=\s]+)\s*=\s*("(?:[^"\\]|\\.)*"|[^;]*)\s*(?=;|$)/g)) {
29
+ if (/** @type {string} */ (parameter[1]).toLowerCase() === 'version') {
30
+ if (version !== undefined)
31
+ throw new TypeError('Duplicate RDF version parameter.');
32
+ version = /** @type {string} */ (parameter[2]).trim().replace(/^"(.*)"$/, '$1').replace(/\\(.)/g, '$1');
33
+ }
34
+ }
35
+ return version === undefined ? resolved : { ...resolved, version };
25
36
  }
26
37
 
27
38
  /** @param {unknown} version */