eyeleng 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -21
- package/dist/browser/eyeleng.browser.js +65 -13
- package/examples/README.md +2 -0
- package/eyeleng.js +119 -30
- package/package.json +1 -1
- package/playground.html +4 -4
- package/reports/w3c-shacl12-rules-earl.ttl +1540 -214
- package/src/api.js +2 -1
- package/src/cli.js +51 -16
- package/src/engine.js +12 -0
- package/src/format.js +31 -2
- package/src/parser.js +15 -5
- package/src/rdfSyntax.js +5 -5
- package/test/api.test.js +35 -0
- package/test/cli.test.js +33 -1
- package/tools/browser-bundle.js +1 -0
- package/tools/bundle.js +3 -1
package/eyeleng.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
queryProgram,
|
|
18
18
|
queryRunOptions,
|
|
19
19
|
formatTriples,
|
|
20
|
-
|
|
20
|
+
formatProof,
|
|
21
21
|
formatBindings,
|
|
22
22
|
toJSON,
|
|
23
23
|
resultTriples,
|
|
@@ -41,15 +41,28 @@
|
|
|
41
41
|
|
|
42
42
|
const VERSION = readPackageVersion();
|
|
43
43
|
|
|
44
|
-
function
|
|
44
|
+
function legacyHelp() {
|
|
45
45
|
return `eyeleng ${VERSION}\n\nA dependency-free JavaScript implementation experiment for the SHACL 1.2 Rules draft, including SRL and RDF Rules syntax front-ends.\n\nUsage:\n eyeleng [options] [file ...]\n\nOptions:\n --all Print the full closure, including input facts\n --json Print JSON instead of compact triples/bindings\n --trace Print derivation trace to stderr, or include it in JSON\n --stats Print iteration and triple counts to stderr\n --check Parse and analyze only; do not run rules\n --strict Treat static warnings as errors, including recursive term generation\n --deps Print rule dependency edges during --check\n --query TEXT Run a raw SRL body pattern over the closure or backward planner\n --query-file FILE Read a raw SRL body pattern from a file\n --query-mode MODE Use auto, forward, or backward query planning (default auto)\n --hybrid Force aggressive hybrid orientation for function-like rules\n --no-hybrid Disable automatic hybrid forward/backward execution\n --max-iterations N Stop after N fixpoint iterations within a recursive layer\n --no-imports Parse IMPORTS/owl:imports but do not load imported rule sets\n --rdf-messages Parse input as an RDF Message Log\n --include-message-facts Include payload facts while parsing RDF Message Logs\n --syntax MODE Use srl, rdf, or auto syntax detection (default auto)\n --ruleset TERM In RDF syntax, run only the selected srl:RuleSet\n --version Print version\n -h, --help Print this help\n\nWith no file arguments, eyeleng reads from stdin.\n`;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function help() {
|
|
49
|
+
return legacyHelp().replace(
|
|
50
|
+
' --trace Print derivation trace to stderr, or include it in JSON',
|
|
51
|
+
' --prove Print proof explanations',
|
|
52
|
+
).replace(
|
|
53
|
+
'Usage:\n eyeleng [options] [file ...]',
|
|
54
|
+
'Usage: eyeleng [options] [file-or-url.n3|- ...]',
|
|
55
|
+
).replace(
|
|
56
|
+
'With no file arguments, eyeleng reads from stdin.',
|
|
57
|
+
'With no input arguments, eyeleng prints this help. Use - to read from stdin.',
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
function parseArgs(argv) {
|
|
49
62
|
const options = {
|
|
50
63
|
all: false,
|
|
51
64
|
json: false,
|
|
52
|
-
|
|
65
|
+
prove: false,
|
|
53
66
|
stats: false,
|
|
54
67
|
check: false,
|
|
55
68
|
strict: false,
|
|
@@ -70,7 +83,7 @@
|
|
|
70
83
|
const arg = argv[i];
|
|
71
84
|
if (arg === '--all') options.all = true;
|
|
72
85
|
else if (arg === '--json') options.json = true;
|
|
73
|
-
else if (arg === '--
|
|
86
|
+
else if (arg === '--prove') options.prove = true;
|
|
74
87
|
else if (arg === '--stats') options.stats = true;
|
|
75
88
|
else if (arg === '--check') options.check = true;
|
|
76
89
|
else if (arg === '--strict') options.strict = true;
|
|
@@ -111,6 +124,8 @@
|
|
|
111
124
|
options.version = true;
|
|
112
125
|
} else if (arg === '-h' || arg === '--help') {
|
|
113
126
|
options.help = true;
|
|
127
|
+
} else if (arg === '-') {
|
|
128
|
+
files.push(arg);
|
|
114
129
|
} else if (arg.startsWith('-')) {
|
|
115
130
|
throw new Error(`Unknown option ${arg}`);
|
|
116
131
|
} else {
|
|
@@ -121,13 +136,26 @@
|
|
|
121
136
|
return { options, files };
|
|
122
137
|
}
|
|
123
138
|
|
|
124
|
-
function readInput(files) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
139
|
+
async function readInput(files, fetchImpl = globalThis.fetch) {
|
|
140
|
+
const inputs = [];
|
|
141
|
+
let readStdin = false;
|
|
142
|
+
for (const spec of files) {
|
|
143
|
+
if (spec === '-') {
|
|
144
|
+
if (readStdin) throw new Error('Standard input (-) may only be specified once');
|
|
145
|
+
readStdin = true;
|
|
146
|
+
inputs.push({ source: fs.readFileSync(0, 'utf8'), filename: '<stdin>', baseIRI: null });
|
|
147
|
+
} else if (/^https?:\/\//i.test(spec)) {
|
|
148
|
+
if (typeof fetchImpl !== 'function') throw new Error(`Cannot fetch URL ${spec}: fetch is unavailable`);
|
|
149
|
+
const response = await fetchImpl(spec);
|
|
150
|
+
if (!response.ok) throw new Error(`Cannot fetch URL ${spec}: HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ''}`);
|
|
151
|
+
inputs.push({ source: await response.text(), filename: spec, baseIRI: spec });
|
|
152
|
+
} else {
|
|
153
|
+
const filename = path.resolve(spec);
|
|
154
|
+
inputs.push({ source: fs.readFileSync(filename, 'utf8'), filename, baseIRI: pathToFileURL(filename).href });
|
|
155
|
+
}
|
|
129
156
|
}
|
|
130
|
-
|
|
157
|
+
if (inputs.length === 1) return inputs[0];
|
|
158
|
+
return { source: inputs.map((input) => input.source).join('\n'), filename: '<input>', baseIRI: null };
|
|
131
159
|
}
|
|
132
160
|
|
|
133
161
|
function createFileImportResolver() {
|
|
@@ -172,7 +200,7 @@
|
|
|
172
200
|
return /^https?:/.test(name) ? compactIRI(name, prefixes) : name;
|
|
173
201
|
}
|
|
174
202
|
|
|
175
|
-
function main(argv = process.argv.slice(2), io = process) {
|
|
203
|
+
async function main(argv = process.argv.slice(2), io = process) {
|
|
176
204
|
try {
|
|
177
205
|
const { options, files } = parseArgs(argv);
|
|
178
206
|
if (options.help) {
|
|
@@ -183,7 +211,11 @@
|
|
|
183
211
|
io.stdout.write(`${VERSION}\n`);
|
|
184
212
|
return 0;
|
|
185
213
|
}
|
|
186
|
-
|
|
214
|
+
if (files.length === 0) {
|
|
215
|
+
io.stdout.write(help());
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
const input = await readInput(files);
|
|
187
219
|
const compiled = compile(input.source, {
|
|
188
220
|
filename: input.filename,
|
|
189
221
|
baseIRI: input.baseIRI,
|
|
@@ -245,15 +277,18 @@
|
|
|
245
277
|
}
|
|
246
278
|
|
|
247
279
|
if (options.json) {
|
|
248
|
-
io.stdout.write(`${JSON.stringify(toJSON(result, { all: options.all,
|
|
280
|
+
io.stdout.write(`${JSON.stringify(toJSON(result, { all: options.all, proof: options.prove, analysis: options.deps }), null, 2)}\n`);
|
|
249
281
|
} else if (result.query) {
|
|
250
282
|
const out = formatBindings(result.query.bindings, result.prefixes, result.query.select);
|
|
251
283
|
if (out) io.stdout.write(`${out}\n`);
|
|
252
284
|
} else {
|
|
253
|
-
if (options.trace && result.trace.length > 0) io.stderr.write(`${formatTrace(result.trace, result.prefixes)}\n`);
|
|
254
285
|
const triples = resultTriples(result, compiled.program, options);
|
|
255
286
|
const out = formatTriples(triples, result.prefixes);
|
|
256
287
|
if (out) io.stdout.write(`${out}\n`);
|
|
288
|
+
if (options.prove) {
|
|
289
|
+
const proof = formatProof(result.trace, result.prefixes);
|
|
290
|
+
if (proof) io.stdout.write(`${out ? '\n' : ''}${proof}\n`);
|
|
291
|
+
}
|
|
257
292
|
}
|
|
258
293
|
|
|
259
294
|
if (options.stats) {
|
|
@@ -271,9 +306,9 @@
|
|
|
271
306
|
}
|
|
272
307
|
}
|
|
273
308
|
|
|
274
|
-
if (require.main === module) process.exitCode =
|
|
309
|
+
if (require.main === module) main().then((code) => { process.exitCode = code; });
|
|
275
310
|
|
|
276
|
-
module.exports = { main, parseArgs, help, VERSION, createFileImportResolver };
|
|
311
|
+
module.exports = { main, parseArgs, readInput, help, VERSION, createFileImportResolver };
|
|
277
312
|
|
|
278
313
|
},
|
|
279
314
|
"src/api.js": function (require, module, exports) {
|
|
@@ -284,7 +319,7 @@
|
|
|
284
319
|
const { parseRdfMessageLog, looksLikeRdfMessageLog } = require('./rdfMessages.js');
|
|
285
320
|
const { evaluate } = require('./engine.js');
|
|
286
321
|
const { analyze } = require('./analyze.js');
|
|
287
|
-
const { formatTriples, sortTriples, toJSON, formatTrace, formatBindings } = require('./format.js');
|
|
322
|
+
const { formatTriples, sortTriples, toJSON, formatTrace, formatProof, formatBindings } = require('./format.js');
|
|
288
323
|
const { runQuery, queryResult, queryProgram, queryRunOptions, shouldUseHybridForQuery } = require('./query.js');
|
|
289
324
|
const { resultTriples } = require('./output.js');
|
|
290
325
|
|
|
@@ -407,6 +442,7 @@
|
|
|
407
442
|
sortTriples,
|
|
408
443
|
toJSON,
|
|
409
444
|
formatTrace,
|
|
445
|
+
formatProof,
|
|
410
446
|
resultTriples,
|
|
411
447
|
};
|
|
412
448
|
|
|
@@ -710,7 +746,7 @@
|
|
|
710
746
|
}
|
|
711
747
|
|
|
712
748
|
parseTripleStatement(options = {}) {
|
|
713
|
-
const subjectNode = this.parseGraphNode(options);
|
|
749
|
+
const subjectNode = this.parseGraphNode({ ...options, position: 'subject' });
|
|
714
750
|
const triples = [...subjectNode.triples];
|
|
715
751
|
triples.push(...this.parsePropertyListForSubject(subjectNode.term, options));
|
|
716
752
|
return triples;
|
|
@@ -724,7 +760,7 @@
|
|
|
724
760
|
if (terminators.some((value) => this.checkValue(value)) || this.checkValue('.')) break;
|
|
725
761
|
const predicate = options.allowPath ? this.parseVerbPathOrSimple(options) : this.parseVerbTerm(options);
|
|
726
762
|
do {
|
|
727
|
-
const objectNode = this.parseGraphNode(options);
|
|
763
|
+
const objectNode = this.parseGraphNode({ ...options, position: 'object' });
|
|
728
764
|
triples.push(...objectNode.triples);
|
|
729
765
|
const baseTriple = { s: subject, p: predicate, o: objectNode.term };
|
|
730
766
|
triples.push(baseTriple);
|
|
@@ -791,6 +827,7 @@
|
|
|
791
827
|
currentReifier = this.parseOptionalReifier(options);
|
|
792
828
|
triples.push({ s: currentReifier, p: iri(RDF_REIFIES), o: reified });
|
|
793
829
|
} else if (this.matchValue('{|')) {
|
|
830
|
+
if (this.checkValue('|}')) throw this.error('Annotation blocks may not be empty');
|
|
794
831
|
const annotationSubject = currentReifier || this.freshGraphNode(options);
|
|
795
832
|
triples.push({ s: annotationSubject, p: iri(RDF_REIFIES), o: reified });
|
|
796
833
|
triples.push(...this.parsePropertyListForSubject(annotationSubject, options, ['|}']));
|
|
@@ -840,7 +877,7 @@
|
|
|
840
877
|
}
|
|
841
878
|
|
|
842
879
|
parseVerbTerm(options = {}) {
|
|
843
|
-
const term = this.parseTerm(options);
|
|
880
|
+
const term = this.parseTerm({ ...options, position: 'predicate' });
|
|
844
881
|
if (term.type !== 'iri' && term.type !== 'var') throw this.error('Expected IRI or variable as predicate');
|
|
845
882
|
return term;
|
|
846
883
|
}
|
|
@@ -963,7 +1000,10 @@
|
|
|
963
1000
|
if (token.value === '<<(') return this.parseTripleTermAfterOpen(options);
|
|
964
1001
|
if (token.value === '<<') throw this.error('Use << s p o >> as a graph node reifier; use <<( s p o )>> for a triple term', token);
|
|
965
1002
|
if (token.type === 'word') {
|
|
966
|
-
if (token.value === 'a')
|
|
1003
|
+
if (token.value === 'a') {
|
|
1004
|
+
if (options.position !== 'predicate') throw this.error('a is only allowed as a predicate', token);
|
|
1005
|
+
return iri(RDF_TYPE);
|
|
1006
|
+
}
|
|
967
1007
|
if (token.value === 'true') return literal(true, XSD_BOOLEAN);
|
|
968
1008
|
if (token.value === 'false') return literal(false, XSD_BOOLEAN);
|
|
969
1009
|
if (token.value.startsWith('_:')) return blankNode(token.value.slice(2));
|
|
@@ -997,7 +1037,13 @@
|
|
|
997
1037
|
return literal(coerceLexicalLiteral(token.value, datatype), datatype, null);
|
|
998
1038
|
}
|
|
999
1039
|
if (this.checkType('word') && /^@[A-Za-z]+(?:-[A-Za-z0-9]+)*(?:--[A-Za-z]+)?$/.test(this.peek().value)) {
|
|
1000
|
-
const
|
|
1040
|
+
const tagToken = this.advance();
|
|
1041
|
+
const rawTag = tagToken.value.slice(1);
|
|
1042
|
+
const direction = rawTag.includes('--') ? rawTag.slice(rawTag.lastIndexOf('--') + 2) : null;
|
|
1043
|
+
if (direction && direction !== 'ltr' && direction !== 'rtl') {
|
|
1044
|
+
throw this.error(`Invalid base direction --${direction}; expected --ltr or --rtl`, tagToken);
|
|
1045
|
+
}
|
|
1046
|
+
const tag = rawTag.toLowerCase();
|
|
1001
1047
|
const [lang, langDir = null] = tag.split('--');
|
|
1002
1048
|
return literal(token.value, null, lang, langDir);
|
|
1003
1049
|
}
|
|
@@ -2776,6 +2822,7 @@
|
|
|
2776
2822
|
const syntaxProfile = String(options.profile || options.profileId || '').toLowerCase();
|
|
2777
2823
|
const rdf12Surface = syntaxProfile === 'turtle' || syntaxProfile === 'trig';
|
|
2778
2824
|
const implicitStatementNodes = new Set();
|
|
2825
|
+
function implicitStatementNodeKey(term) { return `${term.kind}:${term.value}`; }
|
|
2779
2826
|
|
|
2780
2827
|
function freshBlank() { bnodeCounter += 1; return blank(`b${bnodeCounter}`); }
|
|
2781
2828
|
function peek(offset = 0) { return tokens[i + offset]; }
|
|
@@ -2926,7 +2973,7 @@
|
|
|
2926
2973
|
expect('>>');
|
|
2927
2974
|
const node = reifier || freshBlank();
|
|
2928
2975
|
out.push(triple(node, iri(RDF_REIFIES), tripleTerm(s, p, o), graph));
|
|
2929
|
-
|
|
2976
|
+
implicitStatementNodes.add(implicitStatementNodeKey(node));
|
|
2930
2977
|
return node;
|
|
2931
2978
|
}
|
|
2932
2979
|
|
|
@@ -2955,7 +3002,7 @@
|
|
|
2955
3002
|
if (accept(']')) return node;
|
|
2956
3003
|
parsePredicateObjectList(node, out, graph);
|
|
2957
3004
|
expect(']');
|
|
2958
|
-
if (node.kind === 'blank') implicitStatementNodes.add(node
|
|
3005
|
+
if (node.kind === 'blank') implicitStatementNodes.add(implicitStatementNodeKey(node));
|
|
2959
3006
|
return node;
|
|
2960
3007
|
}
|
|
2961
3008
|
|
|
@@ -3033,9 +3080,8 @@
|
|
|
3033
3080
|
if (options3.requireDot) expect('.'); else accept('.');
|
|
3034
3081
|
return;
|
|
3035
3082
|
}
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
if ((peek()?.type === '.' || peek()?.type === '}' || peek()?.type === undefined) && subject.kind === 'blank' && implicitStatementNodes.has(subject.value)) {
|
|
3083
|
+
const subject = parseTerm(out, graph, { noLiteral: !rdf12Surface, noA: true });
|
|
3084
|
+
if ((peek()?.type === '.' || peek()?.type === '}' || peek()?.type === undefined) && implicitStatementNodes.has(implicitStatementNodeKey(subject))) {
|
|
3039
3085
|
if (options3.requireDot) expect('.'); else accept('.');
|
|
3040
3086
|
return;
|
|
3041
3087
|
}
|
|
@@ -4522,6 +4568,7 @@
|
|
|
4522
4568
|
rule: rule.name || `rule#${ruleIndex + 1}`,
|
|
4523
4569
|
triple,
|
|
4524
4570
|
binding,
|
|
4571
|
+
uses: proofUses(rule.body, binding),
|
|
4525
4572
|
});
|
|
4526
4573
|
}
|
|
4527
4574
|
}
|
|
@@ -4532,6 +4579,17 @@
|
|
|
4532
4579
|
return { applications, added };
|
|
4533
4580
|
}
|
|
4534
4581
|
|
|
4582
|
+
function proofUses(body, binding) {
|
|
4583
|
+
return body
|
|
4584
|
+
.filter((clause) => clause.type === 'triple')
|
|
4585
|
+
.map((clause) => ({
|
|
4586
|
+
s: instantiateTerm(clause.triple.s, binding),
|
|
4587
|
+
p: instantiateTerm(clause.triple.p, binding),
|
|
4588
|
+
o: instantiateTerm(clause.triple.o, binding),
|
|
4589
|
+
}))
|
|
4590
|
+
.filter((triple) => ![triple.s, triple.p, triple.o].some((term) => term && term.type === 'var'));
|
|
4591
|
+
}
|
|
4592
|
+
|
|
4535
4593
|
function prepareBodyContext(program, store, context) {
|
|
4536
4594
|
if (!context.hybridBackwardPredicates || context.hybridBackwardPredicates.size === 0) return context;
|
|
4537
4595
|
return {
|
|
@@ -6322,6 +6380,35 @@
|
|
|
6322
6380
|
return trace.map((entry) => `#${entry.iteration} ${entry.rule} => ${formatTriple(entry.triple, prefixes)}`).join('\n');
|
|
6323
6381
|
}
|
|
6324
6382
|
|
|
6383
|
+
function formatProof(trace, prefixes = {}) {
|
|
6384
|
+
if (!trace.length) return '';
|
|
6385
|
+
const lines = ['@prefix pe: <https://eyereasoner.github.io/pe#> .', ''];
|
|
6386
|
+
for (const entry of trace) {
|
|
6387
|
+
const conclusion = formatTriple(entry.triple, prefixes);
|
|
6388
|
+
lines.push(`{ ${conclusion} } pe:why {`);
|
|
6389
|
+
lines.push(` { ${conclusion} }`);
|
|
6390
|
+
lines.push(` pe:by [ pe:rule ${quoteString(entry.rule)} ]${proofDetails(entry, prefixes)} .`);
|
|
6391
|
+
lines.push('}.', '');
|
|
6392
|
+
}
|
|
6393
|
+
return lines.join('\n').trimEnd();
|
|
6394
|
+
}
|
|
6395
|
+
|
|
6396
|
+
function proofDetails(entry, prefixes) {
|
|
6397
|
+
const details = [];
|
|
6398
|
+
const bindings = Object.entries(entry.binding || {}).sort(([a], [b]) => a.localeCompare(b));
|
|
6399
|
+
if (bindings.length > 0) {
|
|
6400
|
+
details.push(`\n pe:binding ${bindings.map(([name, value]) => `[ pe:var ${quoteString(name)}; pe:value ${formatTerm(value, prefixes)} ]`).join(', ')}`);
|
|
6401
|
+
}
|
|
6402
|
+
if (entry.uses && entry.uses.length > 0) {
|
|
6403
|
+
details.push(`\n pe:uses ${entry.uses.map((triple) => `{ ${formatTriple(triple, prefixes)} }`).join(', ')}`);
|
|
6404
|
+
}
|
|
6405
|
+
return details.length ? `;${details.join(';')}` : '';
|
|
6406
|
+
}
|
|
6407
|
+
|
|
6408
|
+
function quoteString(value) {
|
|
6409
|
+
return `"${String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`;
|
|
6410
|
+
}
|
|
6411
|
+
|
|
6325
6412
|
function formatBindings(bindings, prefixes = {}, select = null) {
|
|
6326
6413
|
const columns = select && select.length > 0 ? select : inferColumns(bindings);
|
|
6327
6414
|
return bindings
|
|
@@ -6353,7 +6440,7 @@
|
|
|
6353
6440
|
prefixes: result.prefixes,
|
|
6354
6441
|
diagnostics: result.diagnostics || [],
|
|
6355
6442
|
triples: sortTriples(triples, result.prefixes).map(jsonSafeTriple),
|
|
6356
|
-
|
|
6443
|
+
proof: options.proof ? result.trace : undefined,
|
|
6357
6444
|
};
|
|
6358
6445
|
if (result.query) json.query = jsonSafeValue(result.query);
|
|
6359
6446
|
if (result.analysis && options.analysis) json.analysis = result.analysis;
|
|
@@ -6382,7 +6469,7 @@
|
|
|
6382
6469
|
return value;
|
|
6383
6470
|
}
|
|
6384
6471
|
|
|
6385
|
-
module.exports = { sortTriples, formatTriples, formatTrace, formatBindings, formatBinding, toJSON };
|
|
6472
|
+
module.exports = { sortTriples, formatTriples, formatTrace, formatProof, formatBindings, formatBinding, toJSON };
|
|
6386
6473
|
|
|
6387
6474
|
},
|
|
6388
6475
|
"src/query.js": function (require, module, exports) {
|
|
@@ -6534,5 +6621,7 @@
|
|
|
6534
6621
|
__modules[id](localRequire, module, module.exports);
|
|
6535
6622
|
return module.exports;
|
|
6536
6623
|
}
|
|
6537
|
-
|
|
6624
|
+
Promise.resolve(__require("src/cli.js").main(process.argv.slice(2)))
|
|
6625
|
+
.then((code) => { process.exitCode = code; })
|
|
6626
|
+
.catch((error) => { console.error(error); process.exitCode = 1; });
|
|
6538
6627
|
}());
|
package/package.json
CHANGED
package/playground.html
CHANGED
|
@@ -438,7 +438,7 @@
|
|
|
438
438
|
<div class="checks" aria-label="Reasoning options">
|
|
439
439
|
<label class="toggle"><input id="all-output" type="checkbox" /> Print full closure (--all)</label>
|
|
440
440
|
<label class="toggle"><input id="json-output" type="checkbox" /> JSON output (--json)</label>
|
|
441
|
-
<label class="toggle"><input id="trace-output" type="checkbox" /> Include
|
|
441
|
+
<label class="toggle"><input id="trace-output" type="checkbox" /> Include proof explanations (--prove)</label>
|
|
442
442
|
<label class="toggle"><input id="strict-mode" type="checkbox" /> Treat warnings as errors (--strict)</label>
|
|
443
443
|
<label class="toggle"><input id="check-only" type="checkbox" /> Check only, do not run rules</label>
|
|
444
444
|
<label class="toggle"><input id="show-analysis" type="checkbox" /> Include analysis in JSON</label>
|
|
@@ -946,7 +946,7 @@
|
|
|
946
946
|
if (els.json.checked) {
|
|
947
947
|
text = JSON.stringify(eyeleng.toJSON(result, {
|
|
948
948
|
all: els.all.checked,
|
|
949
|
-
|
|
949
|
+
proof: els.trace.checked,
|
|
950
950
|
analysis: els.analysis.checked,
|
|
951
951
|
}), null, 2);
|
|
952
952
|
} else if (result.query) {
|
|
@@ -955,8 +955,8 @@
|
|
|
955
955
|
const triples = els.all.checked ? result.closure : result.inferred;
|
|
956
956
|
text = eyeleng.formatTriples(triples, result.prefixes);
|
|
957
957
|
if (els.trace.checked && result.trace.length > 0) {
|
|
958
|
-
const
|
|
959
|
-
text = (text ? text + '\n\n' : '') +
|
|
958
|
+
const proof = eyeleng.formatProof(result.trace, result.prefixes);
|
|
959
|
+
text = (text ? text + '\n\n' : '') + proof;
|
|
960
960
|
}
|
|
961
961
|
}
|
|
962
962
|
if (!text) text = '(no output)';
|