@skaterqiang/protege-js 0.1.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/LICENSE +48 -0
  3. package/README.md +287 -0
  4. package/docs/API.md +654 -0
  5. package/docs/design/OWL2-/347/274/272/345/217/243/345/210/206/346/236/220.md +140 -0
  6. package/docs/owl2-rl/OWL2-RL-/350/247/204/345/210/231/347/273/206/345/210/231.md +168 -0
  7. package/docs/owl2-rl/owl2-profiles-spec-zh.html +1914 -0
  8. package/docs/owl2-rl/owl2-profiles-spec.html +1916 -0
  9. package/docs/owl2-rl/rl_rules.json +392 -0
  10. package/main.js +46 -0
  11. package/package.json +76 -0
  12. package/sample/README.md +74 -0
  13. package/sample/case1-ecommerce-risk.js +170 -0
  14. package/sample/case10-ecommerce-customer-service.js +454 -0
  15. package/sample/case2-family-swrl.js +147 -0
  16. package/sample/case3-pharma-safety.js +132 -0
  17. package/sample/case4-knowledge-publishing.js +111 -0
  18. package/sample/case5-obda-profiles.js +153 -0
  19. package/sample/case6-medical-ontology.js +152 -0
  20. package/sample/case7-manufacturing-ppr.js +155 -0
  21. package/sample/case8-real-medical-bfo-ogms.js +353 -0
  22. package/sample/case9-real-manufacturing-iao.js +360 -0
  23. package/sample/ontologies/bfo.owl +1715 -0
  24. package/sample/ontologies/iao.owl +8532 -0
  25. package/sample/ontologies/ogms.owl +4320 -0
  26. package/sample/ontologies/ro-core.owl +1010 -0
  27. package/scripts/verify-api.js +53 -0
  28. package/src/index.js +176 -0
  29. package/src/inference/OWL2ProfileReasoners.js +67 -0
  30. package/src/inference/OWL2RLReasoner.js +65 -0
  31. package/src/inference/ReasonerQueries.js +111 -0
  32. package/src/inference/SWRLReasoner.js +409 -0
  33. package/src/inference/TripleStore.js +82 -0
  34. package/src/inference/rdf.js +83 -0
  35. package/src/inference/rules/owl2el.js +33 -0
  36. package/src/inference/rules/owl2ql.js +29 -0
  37. package/src/inference/rules/owl2rl.js +823 -0
  38. package/src/io/FunctionalSyntaxParser.js +399 -0
  39. package/src/io/FunctionalSyntaxWriter.js +180 -0
  40. package/src/io/ManchesterSyntaxParser.js +398 -0
  41. package/src/io/OWLXMLParser.js +356 -0
  42. package/src/io/OntologyLoader.js +125 -0
  43. package/src/io/RDFGraphToOntology.js +702 -0
  44. package/src/io/RDFXMLParser.js +319 -0
  45. package/src/io/RDFXMLWriter.js +196 -0
  46. package/src/io/SWRLParser.js +150 -0
  47. package/src/io/TurtleParser.js +363 -0
  48. package/src/io/TurtleWriter.js +393 -0
  49. package/src/model/IRI.js +62 -0
  50. package/src/model/OWLAxiom.js +507 -0
  51. package/src/model/OWLClassExpression.js +242 -0
  52. package/src/model/OWLEntity.js +142 -0
  53. package/src/model/OWLLiteral.js +30 -0
  54. package/src/model/OWLModelManager.js +106 -0
  55. package/src/model/OWLOntology.js +119 -0
  56. package/src/model/SWRL.js +152 -0
  57. package/src/model/event/OWLModelManagerEvent.js +33 -0
  58. package/src/model/hierarchy/HierarchyProvider.js +214 -0
  59. package/src/profiles/OWL2Profiles.js +185 -0
  60. package/src/server/public/app.js +97 -0
  61. package/src/server/public/index.html +49 -0
  62. package/src/server/webServer.js +138 -0
  63. package/src/validation/GlobalRestrictionsValidator.js +172 -0
  64. package/test/core.test.js +111 -0
  65. package/test/exports-map.test.js +165 -0
  66. package/test/owl2/axioms.test.js +160 -0
  67. package/test/owl2/classExpressions.test.js +99 -0
  68. package/test/owl2/functional-syntax-writer.test.js +65 -0
  69. package/test/owl2/functional.test.js +113 -0
  70. package/test/owl2/global-restrictions.test.js +76 -0
  71. package/test/owl2/longtail.test.js +74 -0
  72. package/test/owl2/manchester-syntax.test.js +100 -0
  73. package/test/owl2/ontology-loader-imports.test.js +62 -0
  74. package/test/owl2/owlxml-parser.test.js +112 -0
  75. package/test/owl2/profile-reasoners.test.js +108 -0
  76. package/test/owl2/profiles.test.js +66 -0
  77. package/test/owl2/rdf-graph-to-ontology.test.js +177 -0
  78. package/test/owl2/rdfxml-punning.test.js +25 -0
  79. package/test/owl2/rdfxml-writer.test.js +55 -0
  80. package/test/owl2/rdfxml.test.js +91 -0
  81. package/test/owl2/reasoner-queries.test.js +58 -0
  82. package/test/owl2/sample-e2e.test.js +195 -0
  83. package/test/owl2/swrl-parser.test.js +60 -0
  84. package/test/owl2/swrl.test.js +131 -0
  85. package/test/owl2/turtle-writer.test.js +84 -0
  86. package/test/owl2/turtle.test.js +124 -0
  87. package/test/owl2rl/cax.test.js +57 -0
  88. package/test/owl2rl/cls.test.js +210 -0
  89. package/test/owl2rl/dt.test.js +72 -0
  90. package/test/owl2rl/eq.test.js +95 -0
  91. package/test/owl2rl/prp.test.js +198 -0
  92. package/test/owl2rl/scm.test.js +203 -0
@@ -0,0 +1,363 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // TurtleParser — a compact RDF/Turtle parser covering the OWL 2 RL-relevant
5
+ // subset of the W3C Turtle spec (https://www.w3.org/TR/turtle/).
6
+ // Supports: @prefix / @base / PREFIX / BASE, triples with `a`, predicate-object
7
+ // lists, object lists, blank nodes [], collections (), literals with
8
+ // ^^datatype or @lang, numbers, booleans, and comments (#...).
9
+ // Emits raw triples to a TripleStore; mapping to OWL axioms is done elsewhere.
10
+ // ---------------------------------------------------------------------------
11
+
12
+ const { TripleStore } = require('../inference/TripleStore');
13
+
14
+ const RDF_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
15
+ const XSD_NS = 'http://www.w3.org/2001/XMLSchema#';
16
+
17
+ const P = Object.freeze({
18
+ type: RDF_NS + 'type',
19
+ first: RDF_NS + 'first',
20
+ rest: RDF_NS + 'rest',
21
+ nil: RDF_NS + 'nil'
22
+ });
23
+
24
+ const XSD_INTEGER = XSD_NS + 'integer';
25
+ const XSD_DECIMAL = XSD_NS + 'decimal';
26
+ const XSD_DOUBLE = XSD_NS + 'double';
27
+ const XSD_BOOLEAN = XSD_NS + 'boolean';
28
+
29
+ class TurtleParser {
30
+ constructor() {
31
+ this.store = new TripleStore();
32
+ this.prefixes = new Map([
33
+ ['rdf', RDF_NS],
34
+ ['rdfs', 'http://www.w3.org/2000/01/rdf-schema#'],
35
+ ['owl', 'http://www.w3.org/2002/07/owl#'],
36
+ ['xsd', XSD_NS]
37
+ ]);
38
+ this.base = '';
39
+ this._blankCounter = 0;
40
+ }
41
+
42
+ _newBlank() { return '_:b' + (++this._blankCounter); }
43
+
44
+ /** Parse Turtle text. Returns the TripleStore. */
45
+ parse(text) {
46
+ const tokens = this._tokenize(text);
47
+ this._pos = 0;
48
+ this._tokens = tokens;
49
+ while (this._pos < tokens.length) {
50
+ this._statement();
51
+ }
52
+ return this.store;
53
+ }
54
+
55
+ // ---- tokenizer -----------------------------------------------------------
56
+
57
+ _tokenize(text) {
58
+ const out = [];
59
+ let i = 0;
60
+ const n = text.length;
61
+ while (i < n) {
62
+ const ch = text[i];
63
+ // whitespace / comments
64
+ if (/\s/.test(ch)) { i++; continue; }
65
+ if (ch === '#') { while (i < n && text[i] !== '\n') i++; continue; }
66
+ // punctuation
67
+ if (';,.[]()'.includes(ch)) { out.push({ t: ch, v: ch }); i++; continue; }
68
+ if (ch === '^' && text[i + 1] === '^') { out.push({ t: '^^', v: '^^' }); i += 2; continue; }
69
+ // string literal (single/double, possibly long)
70
+ if (ch === '"' || ch === "'") {
71
+ const quote = ch;
72
+ const long = text.substr(i, 3) === quote.repeat(3);
73
+ const endQuote = long ? quote.repeat(3) : quote;
74
+ let j = i + (long ? 3 : 1);
75
+ let value = '';
76
+ while (j < n) {
77
+ if (text.substr(j, endQuote.length) === endQuote) break;
78
+ if (text[j] === '\\' && j + 1 < n) {
79
+ const esc = text[j + 1];
80
+ const map = { n: '\n', t: '\t', r: '\r', '"': '"', "'": "'", '\\': '\\' };
81
+ if (esc === 'u' && j + 5 < n) {
82
+ value += String.fromCharCode(parseInt(text.substr(j + 2, 4), 16));
83
+ j += 6; continue;
84
+ }
85
+ value += map[esc] !== undefined ? map[esc] : esc;
86
+ j += 2;
87
+ continue;
88
+ }
89
+ value += text[j];
90
+ j++;
91
+ }
92
+ j += endQuote.length;
93
+ out.push({ t: 'STRING', v: value });
94
+ i = j;
95
+ continue;
96
+ }
97
+ // IRI_REF <...>
98
+ if (ch === '<') {
99
+ const j = text.indexOf('>', i);
100
+ if (j < 0) throw new Error('Unterminated IRI');
101
+ out.push({ t: 'IRI', v: text.slice(i + 1, j) });
102
+ i = j + 1;
103
+ continue;
104
+ }
105
+ // Blank node label _:name
106
+ if (ch === '_' && text[i + 1] === ':') {
107
+ let j = i + 2;
108
+ while (j < n && /[A-Za-z0-9_-]/.test(text[j])) j++;
109
+ out.push({ t: 'BNODE', v: '_:' + text.slice(i + 2, j) });
110
+ i = j;
111
+ continue;
112
+ }
113
+ // @word keyword (@prefix, @base) or lang tag
114
+ if (ch === '@') {
115
+ let j = i + 1;
116
+ while (j < n && /[A-Za-z0-9_-]/.test(text[j])) j++;
117
+ out.push({ t: 'AT', v: text.slice(i + 1, j) });
118
+ i = j;
119
+ continue;
120
+ }
121
+ // keyword PREFIX / BASE
122
+ if (text.startsWith('PREFIX', i) && /\s/.test(text[i + 6] || ' ')) {
123
+ out.push({ t: 'PREFIX_KW', v: 'PREFIX' }); i += 6; continue;
124
+ }
125
+ if (text.startsWith('BASE', i) && /\s/.test(text[i + 4] || ' ')) {
126
+ out.push({ t: 'BASE_KW', v: 'BASE' }); i += 4; continue;
127
+ }
128
+ // number
129
+ if (/[0-9+-]/.test(ch) && /[0-9]/.test(text[i + 1] || '') || /[0-9]/.test(ch)) {
130
+ let j = i;
131
+ if (/[+-]/.test(text[j])) j++;
132
+ let hasDot = false, hasE = false;
133
+ while (j < n) {
134
+ const c = text[j];
135
+ if (/[0-9]/.test(c)) { j++; continue; }
136
+ if (c === '.' && !hasDot && !hasE && /[0-9]/.test(text[j + 1] || '')) { hasDot = true; j++; continue; }
137
+ if ((c === 'e' || c === 'E') && !hasE) {
138
+ hasE = true; j++;
139
+ if (/[+-]/.test(text[j])) j++;
140
+ continue;
141
+ }
142
+ break;
143
+ }
144
+ const num = text.slice(i, j);
145
+ out.push({ t: 'NUMBER', v: num, hasDot, hasE });
146
+ i = j;
147
+ continue;
148
+ }
149
+ // boolean
150
+ if (text.startsWith('true', i) && !/\w/.test(text[i + 4] || '')) {
151
+ out.push({ t: 'BOOLEAN', v: 'true' }); i += 4; continue;
152
+ }
153
+ if (text.startsWith('false', i) && !/\w/.test(text[i + 5] || '')) {
154
+ out.push({ t: 'BOOLEAN', v: 'false' }); i += 5; continue;
155
+ }
156
+ // keyword `a`
157
+ if (ch === 'a' && !/[A-Za-z0-9_]/.test(text[i + 1] || '')) {
158
+ out.push({ t: 'A', v: 'a' }); i++; continue;
159
+ }
160
+ // prefixed name prefix:local or plain prefix:
161
+ let j = i;
162
+ while (j < n && /[A-Za-z0-9_-]/.test(text[j])) j++;
163
+ if (text[j] === ':') {
164
+ const prefix = text.slice(i, j);
165
+ let k = j + 1;
166
+ while (k < n && /[A-Za-z0-9_\-.]/.test(text[k])) k++;
167
+ const local = text.slice(j + 1, k);
168
+ out.push({ t: 'PNAME', v: prefix + ':' + local });
169
+ i = k;
170
+ continue;
171
+ }
172
+ // bare name (treat as prefixed name without colon -> error unless prefix known)
173
+ // fallthrough: treat as anonymous token
174
+ throw new Error('Unexpected char at ' + i + ': ' + text.slice(i, i + 20));
175
+ }
176
+ return out;
177
+ }
178
+
179
+ _peek() { return this._tokens[this._pos]; }
180
+ _next() { return this._tokens[this._pos++]; }
181
+ _expect(t) {
182
+ const tok = this._next();
183
+ if (!tok || tok.t !== t) throw new Error(`Expected ${t}, got ${tok && tok.t}`);
184
+ return tok;
185
+ }
186
+
187
+ // ---- grammar -------------------------------------------------------------
188
+
189
+ _statement() {
190
+ const tok = this._peek();
191
+ if (!tok) return;
192
+ if (tok.t === 'AT') {
193
+ this._next();
194
+ if (tok.v === 'prefix') {
195
+ const pn = this._expect('PNAME'); // e.g. rdf:
196
+ const iri = this._expect('IRI');
197
+ this.prefixes.set(pn.v.slice(0, -1), iri.v);
198
+ } else if (tok.v === 'base') {
199
+ const iri = this._expect('IRI');
200
+ this.base = iri.v;
201
+ }
202
+ if (this._peek() && this._peek().t === '.') this._next();
203
+ return;
204
+ }
205
+ if (tok.t === 'PREFIX_KW') {
206
+ this._next();
207
+ const pn = this._expect('PNAME');
208
+ const iri = this._expect('IRI');
209
+ this.prefixes.set(pn.v.slice(0, -1), iri.v);
210
+ return;
211
+ }
212
+ if (tok.t === 'BASE_KW') {
213
+ this._next();
214
+ const iri = this._expect('IRI');
215
+ this.base = iri.v;
216
+ return;
217
+ }
218
+ this._triples();
219
+ }
220
+
221
+ _triples() {
222
+ const subject = this._subject();
223
+ this._predicateObjectList(subject);
224
+ this._expect('.');
225
+ }
226
+
227
+ _subject() {
228
+ const tok = this._peek();
229
+ if (tok.t === 'IRI' || tok.t === 'PNAME') return this._iriToken(this._next());
230
+ if (tok.t === 'BNODE') { this._next(); return tok.v; }
231
+ if (tok.t === '[') return this._blankNode();
232
+ if (tok.t === '(') return this._collection();
233
+ throw new Error('Unexpected subject: ' + JSON.stringify(tok));
234
+ }
235
+
236
+ _iriToken(tok) {
237
+ if (tok.t === 'IRI') return this._resolveIRI(tok.v);
238
+ if (tok.t === 'PNAME') {
239
+ const idx = tok.v.indexOf(':');
240
+ const prefix = tok.v.slice(0, idx);
241
+ const local = tok.v.slice(idx + 1);
242
+ if (!this.prefixes.has(prefix)) throw new Error('Unknown prefix: ' + prefix);
243
+ return this.prefixes.get(prefix) + local;
244
+ }
245
+ throw new Error('Not an IRI token: ' + JSON.stringify(tok));
246
+ }
247
+
248
+ _resolveIRI(rel) {
249
+ if (/^https?:/i.test(rel) || /^urn:/i.test(rel)) return rel;
250
+ if (this.base) {
251
+ if (rel.startsWith('#')) return this.base + rel;
252
+ if (rel.startsWith('/')) {
253
+ const m = /^(https?:\/\/[^/]+)/.exec(this.base);
254
+ return m ? m[1] + rel : rel;
255
+ }
256
+ const base = this.base.endsWith('/') ? this.base : this.base + '/';
257
+ return base + rel;
258
+ }
259
+ return rel;
260
+ }
261
+
262
+ _predicateObjectList(subject) {
263
+ while (true) {
264
+ const tok = this._peek();
265
+ if (!tok || tok.t === '.') return;
266
+ // predicate
267
+ let predicate;
268
+ if (tok.t === 'A') { this._next(); predicate = P.type; }
269
+ else if (tok.t === 'IRI' || tok.t === 'PNAME') predicate = this._iriToken(this._next());
270
+ else throw new Error('Expected predicate, got ' + JSON.stringify(tok));
271
+ // object list
272
+ this._objectList(subject, predicate);
273
+ // ; or .
274
+ const sep = this._peek();
275
+ if (sep && sep.t === ';') { this._next(); continue; }
276
+ return;
277
+ }
278
+ }
279
+
280
+ _objectList(subject, predicate) {
281
+ while (true) {
282
+ const obj = this._object();
283
+ if (obj !== undefined && obj !== null) {
284
+ this.store.add(subject, predicate, obj);
285
+ }
286
+ const tok = this._peek();
287
+ if (tok && tok.t === ',') { this._next(); continue; }
288
+ return;
289
+ }
290
+ }
291
+
292
+ _object() {
293
+ const tok = this._peek();
294
+ if (tok.t === 'IRI' || tok.t === 'PNAME') return this._iriToken(this._next());
295
+ if (tok.t === 'BNODE') { this._next(); return tok.v; }
296
+ if (tok.t === 'STRING') {
297
+ this._next();
298
+ let lit = '"' + tok.v.replace(/"/g, '\\"') + '"';
299
+ const next = this._peek();
300
+ if (next && next.t === '^^') {
301
+ this._next();
302
+ const dt = this._iriToken(this._next());
303
+ lit += '^^<' + dt + '>';
304
+ } else if (next && next.t === 'AT') {
305
+ this._next();
306
+ lit += '@' + next.v;
307
+ }
308
+ return lit;
309
+ }
310
+ if (tok.t === 'NUMBER') {
311
+ this._next();
312
+ const dt = tok.hasE ? XSD_DOUBLE : tok.hasDot ? XSD_DECIMAL : XSD_INTEGER;
313
+ return `"${tok.v}"^^<${dt}>`;
314
+ }
315
+ if (tok.t === 'BOOLEAN') {
316
+ this._next();
317
+ return `"${tok.v}"^^<${XSD_BOOLEAN}>`;
318
+ }
319
+ if (tok.t === '[') return this._blankNode();
320
+ if (tok.t === '(') return this._collection();
321
+ throw new Error('Unexpected object: ' + JSON.stringify(tok));
322
+ }
323
+
324
+ _blankNode() {
325
+ this._expect('[');
326
+ const head = this._newBlank();
327
+ const tok = this._peek();
328
+ if (tok && tok.t !== ']') {
329
+ this._predicateObjectList(head);
330
+ }
331
+ this._expect(']');
332
+ return head;
333
+ }
334
+
335
+ _collection() {
336
+ this._expect('(');
337
+ const items = [];
338
+ while (this._peek() && this._peek().t !== ')') {
339
+ items.push(this._object());
340
+ }
341
+ this._expect(')');
342
+ if (items.length === 0) return P.nil;
343
+ // build rdf:first/rest chain
344
+ let head = null;
345
+ let prev = null;
346
+ for (const item of items) {
347
+ const node = this._newBlank();
348
+ if (!head) head = node;
349
+ this.store.add(node, P.first, item);
350
+ if (prev) this.store.add(prev, P.rest, node);
351
+ prev = node;
352
+ }
353
+ this.store.add(prev, P.rest, P.nil);
354
+ return head;
355
+ }
356
+ }
357
+
358
+ /** Convenience: parse Turtle text, return TripleStore. */
359
+ function parseTurtle(text) {
360
+ return new TurtleParser().parse(text);
361
+ }
362
+
363
+ module.exports = { TurtleParser, parseTurtle };