n3 2.11.0 → 2.11.2

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/lib/N3Parser.js CHANGED
@@ -24,7 +24,7 @@ class N3Parser {
24
24
  options.factory && initDataFactory(this, options.factory);
25
25
 
26
26
  // Set supported features depending on the format
27
- const format = typeof options.format === 'string' ? options.format.match(/\w*$/)[0].toLowerCase() : '',
27
+ const format = typeof options.format === 'string' ? options.format.match(/(?:^|\W)(\w*)$/)[1].toLowerCase() : '',
28
28
  isTurtle = /turtle/.test(format),
29
29
  isTriG = /trig/.test(format),
30
30
  isNTriples = /triple/.test(format),
@@ -87,7 +87,9 @@ class N3Parser {
87
87
  if (fragmentPos >= 0) baseIRI = baseIRI.substr(0, fragmentPos);
88
88
  // Set base IRI and its components
89
89
  this._base = baseIRI;
90
- this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI : baseIRI.replace(/[^\/?]*(?:\?.*)?$/, '');
90
+ const queryPos = baseIRI.indexOf('?');
91
+ const path = queryPos < 0 ? baseIRI : baseIRI.substr(0, queryPos);
92
+ this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI : path.substr(0, path.lastIndexOf('/') + 1);
91
93
  baseIRI = baseIRI.match(/^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i);
92
94
  this._baseRoot = baseIRI[0];
93
95
  this._baseScheme = baseIRI[1];
@@ -117,14 +119,15 @@ class N3Parser {
117
119
  inverse: this._inversePredicate,
118
120
  expectOf: this._expectOf,
119
121
  blankPrefix: this._prefixes._,
120
- quantified: this._quantified,
122
+ prefixChanges: this._prefixChanges,
123
+ quantifiedChanges: this._quantifiedChanges,
121
124
  emptyFormula: this._emptyFormula
122
125
  };
123
- // Prefix and base declarations are scoped to their formula
126
+ // Prefix and base declarations are scoped to their formula,
127
+ // so record prefix changes to undo them when the formula ends
124
128
  if (type === 'formula') {
125
- context.prefixes = this._prefixes;
126
129
  context.base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
127
- this._prefixes = Object.create(this._prefixes);
130
+ this._prefixChanges = [];
128
131
  }
129
132
  this._contextStack.push(context);
130
133
  // Every new scope resets the predicate direction
@@ -137,7 +140,7 @@ class N3Parser {
137
140
  // Label the scope with the enclosing formula's blank node
138
141
  // (using a dot as separator, as a blank node label cannot start with it)
139
142
  this._prefixes._ = this._graph ? `${this._graph.value}.` : '.';
140
- this._quantified = Object.create(this._quantified);
143
+ this._quantifiedChanges = [];
141
144
  }
142
145
  // A formula starts empty and must not inherit its parent's subject
143
146
  if (type === 'formula') {
@@ -163,11 +166,16 @@ class N3Parser {
163
166
  if (this._n3Mode) {
164
167
  this._inversePredicate = context.inverse;
165
168
  this._expectOf = context.expectOf;
166
- if (type === 'formula') {
167
- this._prefixes = context.prefixes;
168
- [this._base, this._basePath, this._baseRoot, this._baseScheme] = context.base;
169
- } else this._prefixes._ = context.blankPrefix;
170
- this._quantified = context.quantified;
169
+ if (type === 'formula') [this._base, this._basePath, this._baseRoot, this._baseScheme] = context.base;
170
+ if (this._prefixChanges !== context.prefixChanges) {
171
+ undoChanges(this._prefixes, this._prefixChanges);
172
+ this._prefixChanges = context.prefixChanges;
173
+ }
174
+ this._prefixes._ = context.blankPrefix;
175
+ if (this._quantifiedChanges !== context.quantifiedChanges) {
176
+ undoChanges(this._quantified, this._quantifiedChanges);
177
+ this._quantifiedChanges = context.quantifiedChanges;
178
+ }
171
179
  this._emptyFormula = context.emptyFormula;
172
180
  }
173
181
  }
@@ -976,6 +984,7 @@ class N3Parser {
976
984
  _readPrefixIRI(token) {
977
985
  if (token.type !== 'IRI') return this._error(`Expected IRI to follow prefix "${this._prefix}:"`, token);
978
986
  const prefixNode = this._readEntity(token);
987
+ if (this._prefixChanges !== null) this._prefixChanges.push(this._prefix, this._prefixes[this._prefix]);
979
988
  this._prefixes[this._prefix] = prefixNode.value;
980
989
  this._prefixCallback(this._prefix, prefixNode);
981
990
  return this._readDeclarationPunctuation;
@@ -1046,7 +1055,10 @@ class N3Parser {
1046
1055
  return this._error(`Unexpected ${token.type}`, token);
1047
1056
  }
1048
1057
  // Without explicit quantifiers, map entities to a quantified entity
1049
- if (!this._explicitQuantifiers) this._quantified[entity.id] = this._factory[this._quantifier](this._factory.blankNode().value);
1058
+ if (!this._explicitQuantifiers) {
1059
+ if (this._quantifiedChanges !== null) this._quantifiedChanges.push(entity.id, this._quantified[entity.id]);
1060
+ this._quantified[entity.id] = this._factory[this._quantifier](this._factory.blankNode().value);
1061
+ }
1050
1062
  // With explicit quantifiers, output the reified quantifier
1051
1063
  else {
1052
1064
  // If this is the first item, start a new quantifier list
@@ -1407,7 +1419,10 @@ class N3Parser {
1407
1419
  return this._base + iri;
1408
1420
  // Resolve relative query string IRIs by replacing the query string
1409
1421
  case '?':
1410
- return this._base.replace(/(?:\?.*)?$/, iri);
1422
+ {
1423
+ const queryPos = this._base.indexOf('?');
1424
+ return (queryPos < 0 ? this._base : this._base.substr(0, queryPos)) + iri;
1425
+ }
1411
1426
  // Resolve root-relative IRIs at the root of the base IRI
1412
1427
  case '/':
1413
1428
  // Resolve scheme-relative IRIs to the scheme
@@ -1513,6 +1528,9 @@ class N3Parser {
1513
1528
  this._inversePredicate = false;
1514
1529
  this._expectOf = false;
1515
1530
  this._quantified = Object.create(null);
1531
+ // Changes to prefixes and quantifiers in nested scopes, to undo when leaving them
1532
+ this._prefixChanges = null;
1533
+ this._quantifiedChanges = null;
1516
1534
  this._emptyFormula = false;
1517
1535
  let readToken = token => {
1518
1536
  return this._readCallback = this._readCallback(token);
@@ -1569,8 +1587,15 @@ class N3Parser {
1569
1587
  }
1570
1588
  }
1571
1589
 
1572
- // The empty function
1590
+ // ### `undoChanges` restores the entries of a map from a list of key and previous value pairs
1573
1591
  exports.default = N3Parser;
1592
+ function undoChanges(map, changes) {
1593
+ for (let i = changes.length - 2; i >= 0; i -= 2) {
1594
+ if (changes[i + 1] === undefined) delete map[changes[i]];else map[changes[i]] = changes[i + 1];
1595
+ }
1596
+ }
1597
+
1598
+ // The empty function
1574
1599
  function noop() {}
1575
1600
 
1576
1601
  // Initializes the parser with the given data factory
package/lib/N3Store.js CHANGED
@@ -37,7 +37,10 @@ function merge(target, source, depth = 4) {
37
37
  if (!(key in target)) {
38
38
  size++;
39
39
  target[key] = depth === 0 ? null : merge(Object.create(null), source[key], depth - 1);
40
- } else if (depth !== 0) target[key] = merge(target[key], source[key], depth - 1);
40
+ }
41
+ // Merge into the existing object in place,
42
+ // as graph objects are frozen and cannot be reassigned
43
+ else if (depth !== 0) merge(target[key], source[key], depth - 1);
41
44
  }
42
45
  // Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
43
46
  if (depth <= 2) target[SIZE] = size;
@@ -945,16 +948,20 @@ class N3Store {
945
948
  }
946
949
 
947
950
  // Store the list item and continue with parent
948
- if (!first) malformed = onError(current, 'has no list head');else items.unshift(first.object);
951
+ if (!first) malformed = onError(current, 'has no list head');else items.push(first.object);
949
952
  current = parent && parent.subject;
950
953
  }
951
954
 
952
955
  // Don't remove any quads if the list is malformed
953
956
  if (malformed) remove = false;else {
957
+ // Items were collected from the tail to the head
958
+ items.reverse();
954
959
  // Store the list under the value of its head
955
960
  if (head) lists[head[headPos].value] = items;
956
961
  // Leave lists with extra arcs fully intact; otherwise queue this list once.
957
- if (remove && !extraArcs) toRemove.push(...listQuads);
962
+ if (remove && !extraArcs) {
963
+ for (let i = 0; i < listQuads.length; i++) toRemove.push(listQuads[i]);
964
+ }
958
965
  }
959
966
  });
960
967
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.11.0",
3
+ "version": "2.11.2",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
@@ -60,33 +60,17 @@
60
60
  "test": "jest",
61
61
  "lint": "eslint src perf test spec",
62
62
  "prepare": "npm run build",
63
- "spec": "npm run spec-1-1 && npm run spec-1-2 && npm run spec-n3",
64
- "spec-1-1": "npm run spec-1-1-turtle && npm run spec-1-1-ntriples && npm run spec-1-1-nquads && npm run spec-1-1-trig",
63
+ "spec": "node spec/run.js",
65
64
  "spec-1-1-earl": "npm run spec-1-1-earl-turtle && npm run spec-1-1-earl-ntriples && npm run spec-1-1-earl-nquads && npm run spec-1-1-earl-trig",
66
- "spec-1-1-ntriples": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-triples/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/",
67
- "spec-1-1-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-quads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/",
68
- "spec-1-1-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-turtle/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ --skip \"(bad-numeric-escape|bareword_decimal)\"",
69
- "spec-1-1-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-trig/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ --skip \"(bad-numeric-escape|IRI-resolution-01)\"",
70
65
  "spec-1-1-earl-ntriples": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-triples/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-ntriples.ttl",
71
66
  "spec-1-1-earl-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-quads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-nquads.ttl",
72
67
  "spec-1-1-earl-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-turtle/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-turtle.ttl",
73
68
  "spec-1-1-earl-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-trig/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-trig.ttl",
74
- "spec-1-2": "npm run spec-1-2-turtle && npm run spec-1-2-ntriples && npm run spec-1-2-nquads && npm run spec-1-2-trig && npm run spec-1-2-turtle-eval && npm run spec-1-2-trig-eval",
75
69
  "spec-1-2-earl": "npm run spec-1-2-earl-turtle && npm run spec-1-2-earl-ntriples && npm run spec-1-2-earl-nquads && npm run spec-1-2-earl-trig",
76
- "spec-1-2-ntriples": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-triples/syntax/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/",
77
- "spec-1-2-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-quads/syntax/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/",
78
- "spec-1-2-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/",
79
- "spec-1-2-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/syntax/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/",
80
- "spec-1-2-turtle-eval": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/eval/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/",
81
- "spec-1-2-trig-eval": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/eval/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/",
82
70
  "spec-1-2-earl-ntriples": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-triples/syntax/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-ntriples.ttl",
83
71
  "spec-1-2-earl-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-quads/syntax/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-nquads.ttl",
84
72
  "spec-1-2-earl-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-turtle.ttl",
85
73
  "spec-1-2-earl-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/syntax/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-trig.ttl",
86
- "spec-n3": "npm run spec-n3-parser && npm run spec-n3-extended",
87
- "spec-n3-fetch": "sh scripts/fetch-n3-tests.sh",
88
- "spec-n3-parser": "npm run spec-n3-fetch && rdf-test-suite spec/parser.js https://w3c-cg.github.io/N3/tests/N3Tests/manifest-parser.ttl -i '{ \"format\": \"text/n3\" }' -m 'https://w3c-cg.github.io/N3/tests/~.n3-tests/tests/'",
89
- "spec-n3-extended": "npm run spec-n3-fetch && rdf-test-suite spec/parser.js https://w3c-cg.github.io/N3/tests/N3Tests/manifest-extended.ttl -i '{ \"format\": \"text/n3\" }' -m 'https://w3c-cg.github.io/N3/tests/~.n3-tests/tests/'",
90
74
  "spec-clean": "rm -rf .rdf-test-suite-cache/ .n3-tests/",
91
75
  "docs": "cd src && docco *.js -o ../docs && cd .."
92
76
  },
@@ -126,7 +110,28 @@
126
110
  },
127
111
  "release": {
128
112
  "branches": [
129
- "main"
113
+ "main",
114
+ {
115
+ "name": "next-major",
116
+ "prerelease": "alpha",
117
+ "channel": "alpha"
118
+ }
119
+ ],
120
+ "plugins": [
121
+ [
122
+ "@semantic-release/commit-analyzer",
123
+ {
124
+ "preset": "conventionalcommits"
125
+ }
126
+ ],
127
+ [
128
+ "@semantic-release/release-notes-generator",
129
+ {
130
+ "preset": "conventionalcommits"
131
+ }
132
+ ],
133
+ "@semantic-release/npm",
134
+ "@semantic-release/github"
130
135
  ]
131
136
  },
132
137
  "publishConfig": {
package/src/BaseIRI.js CHANGED
@@ -4,7 +4,9 @@ import { escapeRegex } from './Util';
4
4
  // - file: IRIs (which could also use backslashes)
5
5
  // - IRIs containing /. or /.. or //
6
6
  const BASE_UNSUPPORTED = /^:?[^:?#]*(?:[?#]|$)|^file:|^[^:]*:\/*[^?#]+?\/(?:\.\.?(?:\/|$)|\/)/i;
7
- const SUFFIX_SUPPORTED = /^(?:(?:[^/?#]{3,}|\.?[^/?#.]\.?)(?:\/[^/?#]{3,}|\.?[^/?#.]\.?)*\/?)?(?:[?#]|$)/;
7
+ // Supported suffixes have a first path segment other than . or ..,
8
+ // and further path segments of at least 3 characters
9
+ const SUFFIX_SUPPORTED = /^(?:(?!\.\.?(?:[/?#]|$))[^/?#]+(?:\/[^/?#]{3,})*\/?)?(?:[?#]|$)/;
8
10
  const CURRENT = './';
9
11
  const PARENT = '../';
10
12
  const QUERY = '?';
@@ -88,8 +90,10 @@ export default class BaseIRI {
88
90
  // Don't abbreviate unsupported path
89
91
  if (parentPath !== QUERY && !SUFFIX_SUPPORTED.test(suffix))
90
92
  return iri;
91
- // Omit ./ with fragment or query string
92
- if (parentPath === CURRENT && /^[^?#]/.test(suffix))
93
+ // Omit ./ with fragment or query string,
94
+ // unless the first segment has a colon and would be read as a scheme
95
+ if (parentPath === CURRENT && /^[^?#]/.test(suffix) &&
96
+ (suffix.indexOf(':') < 0 || !/^[^/?#]*:/.test(suffix)))
93
97
  return suffix;
94
98
  // Append suffix to relative parent path
95
99
  return parentPath + suffix;
@@ -499,7 +499,8 @@ export function fromTerm(term) {
499
499
  case 'BlankNode': return blankNode(term.value);
500
500
  case 'Variable': return variable(term.value);
501
501
  case 'DefaultGraph': return DEFAULTGRAPH;
502
- case 'Literal': return literal(term.value, term.language || term.datatype);
502
+ case 'Literal': return literal(term.value, !term.language ? term.datatype :
503
+ term.direction ? { language: term.language, direction: term.direction } : term.language);
503
504
  case 'Quad': return fromQuad(term);
504
505
  default: throw new Error(`Unexpected termType: ${term.termType}`);
505
506
  }