n3 1.18.0 → 1.20.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.
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ exports.getRulesFromDataset = getRulesFromDataset;
8
+ var _N3DataFactory = _interopRequireDefault(require("./N3DataFactory"));
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ /**
11
+ * Gets rules from a dataset. This will only collect horn rules declared using log:implies.
12
+ */
13
+ function getRulesFromDataset(dataset) {
14
+ const rules = [];
15
+ for (const {
16
+ subject,
17
+ object
18
+ } of dataset.match(null, _N3DataFactory.default.namedNode('http://www.w3.org/2000/10/swap/log#implies'), null, _N3DataFactory.default.defaultGraph())) {
19
+ const premise = [...dataset.match(null, null, null, subject)];
20
+ const conclusion = [...dataset.match(null, null, null, object)];
21
+ rules.push({
22
+ premise,
23
+ conclusion
24
+ });
25
+ }
26
+ return rules;
27
+ }
28
+ class N3Reasoner {
29
+ constructor(store) {
30
+ this._store = store;
31
+ }
32
+ _add(subject, predicate, object, graphItem, cb) {
33
+ // Only add to the remaining indexes if there is not already a value in the index
34
+ if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
35
+ this._store._addToIndex(graphItem.predicates, predicate, object, subject);
36
+ this._store._addToIndex(graphItem.objects, object, subject, predicate);
37
+ cb();
38
+ }
39
+
40
+ // eslint-disable-next-line no-warning-comments
41
+ _evaluatePremise(rule, content, cb, i = 0) {
42
+ let v1, v2, value, index1, index2;
43
+ const [val0, val1, val2] = rule.premise[i].value,
44
+ index = content[rule.premise[i].content];
45
+ const v0 = !(value = val0.value);
46
+ for (value in v0 ? index : {
47
+ [value]: index[value]
48
+ }) {
49
+ if (index1 = index[value]) {
50
+ if (v0) val0.value = Number(value);
51
+ v1 = !(value = val1.value);
52
+ for (value in v1 ? index1 : {
53
+ [value]: index1[value]
54
+ }) {
55
+ if (index2 = index1[value]) {
56
+ if (v1) val1.value = Number(value);
57
+ v2 = !(value = val2.value);
58
+ for (value in v2 ? index2 : {
59
+ [value]: index2[value]
60
+ }) {
61
+ if (v2) val2.value = Number(value);
62
+ if (i === rule.premise.length - 1) rule.conclusion.forEach(c => {
63
+ // eslint-disable-next-line max-nested-callbacks
64
+ this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
65
+ cb(c);
66
+ });
67
+ });else this._evaluatePremise(rule, content, cb, i + 1);
68
+ }
69
+ if (v2) val2.value = null;
70
+ }
71
+ }
72
+ if (v1) val1.value = null;
73
+ }
74
+ }
75
+ if (v0) val0.value = null;
76
+ }
77
+ _evaluateRules(rules, content, cb) {
78
+ for (let i = 0; i < rules.length; i++) {
79
+ this._evaluatePremise(rules[i], content, cb);
80
+ }
81
+ }
82
+
83
+ // A naive reasoning algorithm where rules are just applied by repeatedly applying rules
84
+ // until no more evaluations are made
85
+ _reasonGraphNaive(rules, content) {
86
+ const newRules = [];
87
+ function addRule(conclusion) {
88
+ if (conclusion.next) conclusion.next.forEach(rule => {
89
+ newRules.push([conclusion.subject.value, conclusion.predicate.value, conclusion.object.value, rule]);
90
+ });
91
+ }
92
+
93
+ // eslint-disable-next-line func-style
94
+ const addConclusions = conclusion => {
95
+ conclusion.forEach(c => {
96
+ // eslint-disable-next-line max-nested-callbacks
97
+ this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
98
+ addRule(c);
99
+ });
100
+ });
101
+ };
102
+ this._evaluateRules(rules, content, addRule);
103
+ let r;
104
+ while ((r = newRules.pop()) !== undefined) {
105
+ const [subject, predicate, object, rule] = r;
106
+ const v1 = rule.basePremise.subject.value;
107
+ if (!v1) rule.basePremise.subject.value = subject;
108
+ const v2 = rule.basePremise.predicate.value;
109
+ if (!v2) rule.basePremise.predicate.value = predicate;
110
+ const v3 = rule.basePremise.object.value;
111
+ if (!v3) rule.basePremise.object.value = object;
112
+ if (rule.premise.length === 0) {
113
+ addConclusions(rule.conclusion);
114
+ } else {
115
+ this._evaluatePremise(rule, content, addRule);
116
+ }
117
+ if (!v1) rule.basePremise.subject.value = null;
118
+ if (!v2) rule.basePremise.predicate.value = null;
119
+ if (!v3) rule.basePremise.object.value = null;
120
+ }
121
+ }
122
+ _createRule({
123
+ premise,
124
+ conclusion
125
+ }) {
126
+ const varMapping = {};
127
+ const toId = value => value.termType === 'Variable' ?
128
+ // If the term is a variable, then create an empty object that values can be placed into
129
+ varMapping[value.value] = varMapping[value.value] || {} :
130
+ // If the term is not a variable, then set the ID value
131
+ {
132
+ value: this._store._termToNewNumericId(value)
133
+ };
134
+
135
+ // eslint-disable-next-line func-style
136
+ const t = term => ({
137
+ subject: toId(term.subject),
138
+ predicate: toId(term.predicate),
139
+ object: toId(term.object)
140
+ });
141
+ return {
142
+ premise: premise.map(p => t(p)),
143
+ conclusion: conclusion.map(p => t(p)),
144
+ variables: Object.values(varMapping)
145
+ };
146
+ }
147
+ reason(rules) {
148
+ if (!Array.isArray(rules)) {
149
+ rules = getRulesFromDataset(rules);
150
+ }
151
+ rules = rules.map(rule => this._createRule(rule));
152
+ for (const r1 of rules) {
153
+ for (const r2 of rules) {
154
+ for (let i = 0; i < r2.premise.length; i++) {
155
+ const p = r2.premise[i];
156
+ for (const c of r1.conclusion) {
157
+ if (termEq(p.subject, c.subject) && termEq(p.predicate, c.predicate) && termEq(p.object, c.object)) {
158
+ const set = new Set();
159
+ const premise = [];
160
+
161
+ // Since these *will* be substituted when we apply the rule,
162
+ // we need to do this, so that we index correctly in the subsequent section
163
+ p.subject.value = p.subject.value || 1;
164
+ p.object.value = p.object.value || 1;
165
+ p.predicate.value = p.predicate.value || 1;
166
+ for (let j = 0; j < r2.premise.length; j++) {
167
+ if (j !== i) {
168
+ premise.push(getIndex(r2.premise[j], set));
169
+ }
170
+ }
171
+
172
+ // eslint-disable-next-line no-warning-comments
173
+ // TODO: Create new rule, with new indexing
174
+ // Future, 'collapse' the next statements when they share a premise/base-premise
175
+ (c.next = c.next || []).push({
176
+ premise,
177
+ conclusion: r2.conclusion,
178
+ // This is a single premise of the form { subject, predicate, object },
179
+ // which we can use to instantiate the rule using the new data that was emitted
180
+ basePremise: p
181
+ });
182
+ }
183
+ r2.variables.forEach(v => {
184
+ v.value = null;
185
+ });
186
+ }
187
+ }
188
+ }
189
+ }
190
+ for (const rule of rules) {
191
+ const set = new Set();
192
+ rule.premise = rule.premise.map(p => getIndex(p, set));
193
+ }
194
+ const graphs = this._store._getGraphs();
195
+ for (const graphId in graphs) {
196
+ this._reasonGraphNaive(rules, graphs[graphId]);
197
+ }
198
+ this._store._size = null;
199
+ }
200
+ }
201
+ exports.default = N3Reasoner;
202
+ function getIndex({
203
+ subject,
204
+ predicate,
205
+ object
206
+ }, set) {
207
+ const s = subject.value || set.has(subject) || (set.add(subject), false);
208
+ const p = predicate.value || set.has(predicate) || (set.add(predicate), false);
209
+ const o = object.value || set.has(object) || (set.add(object), false);
210
+ return !s && p ? {
211
+ content: 'predicates',
212
+ value: [predicate, object, subject]
213
+ } : o ? {
214
+ content: 'objects',
215
+ value: [object, subject, predicate]
216
+ } : {
217
+ content: 'subjects',
218
+ value: [subject, predicate, object]
219
+ };
220
+ }
221
+ function termEq(t1, t2) {
222
+ if (t1.value === null) {
223
+ t1.value = t2.value;
224
+ }
225
+ return t1.value === t2.value;
226
+ }
package/lib/N3Store.js CHANGED
@@ -8,6 +8,7 @@ var _readableStream = require("readable-stream");
8
8
  var _N3DataFactory = _interopRequireWildcard(require("./N3DataFactory"));
9
9
  var _IRIs = _interopRequireDefault(require("./IRIs"));
10
10
  var _N3Util = require("./N3Util");
11
+ var _N3Writer = _interopRequireDefault(require("./N3Writer"));
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
14
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -495,7 +496,7 @@ class N3Store {
495
496
  // Setting any field to `undefined` or `null` indicates a wildcard.
496
497
  forEach(callback, subject, predicate, object, graph) {
497
498
  this.some(quad => {
498
- callback(quad);
499
+ callback(quad, this);
499
500
  return false;
500
501
  }, subject, predicate, object, graph);
501
502
  }
@@ -504,12 +505,7 @@ class N3Store {
504
505
  // and returns `true` if it returns truthy for all them.
505
506
  // Setting any field to `undefined` or `null` indicates a wildcard.
506
507
  every(callback, subject, predicate, object, graph) {
507
- let some = false;
508
- const every = !this.some(quad => {
509
- some = true;
510
- return !callback(quad);
511
- }, subject, predicate, object, graph);
512
- return some && every;
508
+ return !this.some(quad => !callback(quad, this), subject, predicate, object, graph);
513
509
  }
514
510
 
515
511
  // ### `some` executes the callback on all quads,
@@ -743,6 +739,149 @@ class N3Store {
743
739
  return lists;
744
740
  }
745
741
 
742
+ /**
743
+ * Returns `true` if the current dataset is a superset of the given dataset; in other words, returns `true` if
744
+ * the given dataset is a subset of, i.e., is contained within, the current dataset.
745
+ *
746
+ * Blank Nodes will be normalized.
747
+ */
748
+ addAll(quads) {
749
+ if (Array.isArray(quads)) this.addQuads(quads);else {
750
+ for (const quad of quads) this.add(quad);
751
+ }
752
+ return this;
753
+ }
754
+
755
+ /**
756
+ * Returns `true` if the current dataset is a superset of the given dataset; in other words, returns `true` if
757
+ * the given dataset is a subset of, i.e., is contained within, the current dataset.
758
+ *
759
+ * Blank Nodes will be normalized.
760
+ */
761
+ contains(other) {
762
+ return other.every(quad => this.has(quad));
763
+ }
764
+
765
+ /**
766
+ * This method removes the quads in the current dataset that match the given arguments.
767
+ *
768
+ * The logic described in {@link https://rdf.js.org/dataset-spec/#quad-matching|Quad Matching} is applied for each
769
+ * quad in this dataset, to select the quads which will be deleted.
770
+ *
771
+ * @param subject The optional exact subject to match.
772
+ * @param predicate The optional exact predicate to match.
773
+ * @param object The optional exact object to match.
774
+ * @param graph The optional exact graph to match.
775
+ */
776
+ deleteMatches(subject, predicate, object, graph) {
777
+ for (const quad of this.match(subject, predicate, object, graph)) this.removeQuad(quad);
778
+ return this;
779
+ }
780
+
781
+ /**
782
+ * Returns a new dataset that contains all quads from the current dataset that are not included in the given dataset.
783
+ */
784
+ difference(other) {
785
+ return this.filter(quad => !other.has(quad));
786
+ }
787
+
788
+ /**
789
+ * Returns true if the current dataset contains the same graph structure as the given dataset.
790
+ *
791
+ * Blank Nodes will be normalized.
792
+ */
793
+ equals(other) {
794
+ return other === this || this.size === other.size && this.contains(other);
795
+ }
796
+
797
+ /**
798
+ * Creates a new dataset with all the quads that pass the test implemented by the provided `iteratee`.
799
+ *
800
+ * This method is aligned with Array.prototype.filter() in ECMAScript-262.
801
+ */
802
+ filter(iteratee) {
803
+ const store = new N3Store();
804
+ for (const quad of this) if (iteratee(quad, this)) store.add(quad);
805
+ return store;
806
+ }
807
+
808
+ /**
809
+ * Returns a new dataset containing all quads from the current dataset that are also included in the given dataset.
810
+ */
811
+ intersection(other) {
812
+ return this.filter(quad => other.has(quad));
813
+ }
814
+
815
+ /**
816
+ * Returns a new dataset containing all quads returned by applying `iteratee` to each quad in the current dataset.
817
+ */
818
+ map(iteratee) {
819
+ const store = new N3Store();
820
+ for (const quad of this) store.add(iteratee(quad, this));
821
+ return store;
822
+ }
823
+
824
+ /**
825
+ * This method calls the `iteratee` method on each `quad` of the `Dataset`. The first time the `iteratee` method
826
+ * is called, the `accumulator` value is the `initialValue`, or, if not given, equals the first quad of the `Dataset`.
827
+ * The return value of each call to the `iteratee` method is used as the `accumulator` value for the next call.
828
+ *
829
+ * This method returns the return value of the last `iteratee` call.
830
+ *
831
+ * This method is aligned with `Array.prototype.reduce()` in ECMAScript-262.
832
+ */
833
+ reduce(callback, initialValue) {
834
+ const iter = this.readQuads();
835
+ let accumulator = initialValue === undefined ? iter.next().value : initialValue;
836
+ for (const quad of iter) accumulator = callback(accumulator, quad, this);
837
+ return accumulator;
838
+ }
839
+
840
+ /**
841
+ * Returns the set of quads within the dataset as a host-language-native sequence, for example an `Array` in
842
+ * ECMAScript-262.
843
+ *
844
+ * Since a `Dataset` is an unordered set, the order of the quads within the returned sequence is arbitrary.
845
+ */
846
+ toArray() {
847
+ return this.getQuads();
848
+ }
849
+
850
+ /**
851
+ * Returns an N-Quads string representation of the dataset, preprocessed with the
852
+ * {@link https://json-ld.github.io/normalization/spec/|RDF Dataset Normalization} algorithm.
853
+ */
854
+ toCanonical() {
855
+ throw new Error('not implemented');
856
+ }
857
+
858
+ /**
859
+ * Returns a stream that contains all quads of the dataset.
860
+ */
861
+ toStream() {
862
+ return this.match();
863
+ }
864
+
865
+ /**
866
+ * Returns an N-Quads string representation of the dataset.
867
+ *
868
+ * No prior normalization is required, therefore the results for the same quads may vary depending on the `Dataset`
869
+ * implementation.
870
+ */
871
+ toString() {
872
+ return new _N3Writer.default().quadsToString(this);
873
+ }
874
+
875
+ /**
876
+ * Returns a new `Dataset` that is a concatenation of this dataset and the quads given as an argument.
877
+ */
878
+ union(quads) {
879
+ const store = new N3Store();
880
+ store.addAll(this);
881
+ store.addAll(quads);
882
+ return store;
883
+ }
884
+
746
885
  // ### Store is an iterable.
747
886
  // Can be used where iterables are expected: for...of loops, array spread operator,
748
887
  // `yield*`, and destructuring assignment (order is not guaranteed).
@@ -804,6 +943,60 @@ class DatasetCoreAndReadableStream extends _readableStream.Readable {
804
943
  this.push(value);
805
944
  }
806
945
  }
946
+ addAll(quads) {
947
+ return this.filtered.addAll(quads);
948
+ }
949
+ contains(other) {
950
+ return this.filtered.contains(other);
951
+ }
952
+ deleteMatches(subject, predicate, object, graph) {
953
+ return this.filtered.deleteMatches(subject, predicate, object, graph);
954
+ }
955
+ difference(other) {
956
+ return this.filtered.difference(other);
957
+ }
958
+ equals(other) {
959
+ return this.filtered.equals(other);
960
+ }
961
+ every(callback, subject, predicate, object, graph) {
962
+ return this.filtered.every(callback, subject, predicate, object, graph);
963
+ }
964
+ filter(iteratee) {
965
+ return this.filtered.filter(iteratee);
966
+ }
967
+ forEach(callback, subject, predicate, object, graph) {
968
+ return this.filtered.forEach(callback, subject, predicate, object, graph);
969
+ }
970
+ import(stream) {
971
+ return this.filtered.import(stream);
972
+ }
973
+ intersection(other) {
974
+ return this.filtered.intersection(other);
975
+ }
976
+ map(iteratee) {
977
+ return this.filtered.map(iteratee);
978
+ }
979
+ some(callback, subject, predicate, object, graph) {
980
+ return this.filtered.some(callback, subject, predicate, object, graph);
981
+ }
982
+ toCanonical() {
983
+ return this.filtered.toCanonical();
984
+ }
985
+ toStream() {
986
+ return this._filtered ? this._filtered.toStream() : this.n3Store.match(this.subject, this.predicate, this.object, this.graph);
987
+ }
988
+ union(quads) {
989
+ return this._filtered ? this._filtered.union(quads) : this.n3Store.match(this.subject, this.predicate, this.object, this.graph).addAll(quads);
990
+ }
991
+ toArray() {
992
+ return this._filtered ? this._filtered.toArray() : this.n3Store.getQuads(this.subject, this.predicate, this.object, this.graph);
993
+ }
994
+ reduce(callback, initialValue) {
995
+ return this.filtered.reduce(callback, initialValue);
996
+ }
997
+ toString() {
998
+ return new _N3Writer.default().quadsToString(this);
999
+ }
807
1000
  add(quad) {
808
1001
  return this.filtered.add(quad);
809
1002
  }
package/lib/N3Writer.js CHANGED
@@ -136,9 +136,9 @@ class N3Writer {
136
136
 
137
137
  // ### `quadsToString` serializes an array of quads as a string
138
138
  quadsToString(quads) {
139
- return quads.map(t => {
140
- return this.quadToString(t.subject, t.predicate, t.object, t.graph);
141
- }).join('');
139
+ let quadsString = '';
140
+ for (const quad of quads) quadsString += this.quadToString(quad.subject, quad.predicate, quad.object, quad.graph);
141
+ return quadsString;
142
142
  }
143
143
 
144
144
  // ### `_encodeSubject` represents a subject
package/lib/index.js CHANGED
@@ -57,6 +57,12 @@ Object.defineProperty(exports, "Quad", {
57
57
  return _N3DataFactory.Quad;
58
58
  }
59
59
  });
60
+ Object.defineProperty(exports, "Reasoner", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _N3Reasoner.default;
64
+ }
65
+ });
60
66
  Object.defineProperty(exports, "Store", {
61
67
  enumerable: true,
62
68
  get: function () {
@@ -107,6 +113,12 @@ Object.defineProperty(exports, "Writer", {
107
113
  }
108
114
  });
109
115
  exports.default = void 0;
116
+ Object.defineProperty(exports, "getRulesFromDataset", {
117
+ enumerable: true,
118
+ get: function () {
119
+ return _N3Reasoner.getRulesFromDataset;
120
+ }
121
+ });
110
122
  Object.defineProperty(exports, "termFromId", {
111
123
  enumerable: true,
112
124
  get: function () {
@@ -124,6 +136,7 @@ var _N3Parser = _interopRequireDefault(require("./N3Parser"));
124
136
  var _N3Writer = _interopRequireDefault(require("./N3Writer"));
125
137
  var _N3Store = _interopRequireWildcard(require("./N3Store"));
126
138
  var _N3StoreFactory = _interopRequireDefault(require("./N3StoreFactory"));
139
+ var _N3Reasoner = _interopRequireWildcard(require("./N3Reasoner"));
127
140
  var _N3StreamParser = _interopRequireDefault(require("./N3StreamParser"));
128
141
  var _N3StreamWriter = _interopRequireDefault(require("./N3StreamWriter"));
129
142
  var Util = _interopRequireWildcard(require("./N3Util"));
@@ -144,6 +157,7 @@ var _default = exports.default = {
144
157
  StreamParser: _N3StreamParser.default,
145
158
  StreamWriter: _N3StreamWriter.default,
146
159
  Util,
160
+ Reasoner: _N3Reasoner.default,
147
161
  DataFactory: _N3DataFactory.default,
148
162
  Term: _N3DataFactory.Term,
149
163
  NamedNode: _N3DataFactory.NamedNode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "1.18.0",
3
+ "version": "1.20.0",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
@@ -37,6 +37,7 @@
37
37
  "arrayify-stream": "^1.0.0",
38
38
  "browserify": "^17.0.0",
39
39
  "colors": "^1.1.2",
40
+ "deep-taxonomy-benchmark": "^1.2.0",
40
41
  "docco": "^0.9.1",
41
42
  "eslint": "^5.14.1",
42
43
  "eslint-plugin-import": "^2.29.1",