eyeling 1.28.9 → 1.29.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/README.md +73 -2
- package/dist/browser/eyeling.browser.js +1284 -33
- package/dist/browser/index.mjs +10 -0
- package/eyeling.js +1284 -33
- package/index.d.ts +59 -0
- package/index.js +17 -0
- package/lib/cli.js +309 -33
- package/lib/engine.js +279 -0
- package/lib/entry.js +4 -0
- package/lib/rdfjs.js +1 -0
- package/lib/store.js +688 -0
- package/package.json +8 -3
- package/test/store.test.js +167 -0
- package/test/stream_messages.test.js +13 -0
- package/tools/bundle.js +10 -0
package/index.d.ts
CHANGED
|
@@ -151,6 +151,14 @@ declare module 'eyeling' {
|
|
|
151
151
|
document?: EyelingAstBundle;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
export interface StoreOptions {
|
|
155
|
+
name?: string;
|
|
156
|
+
clear?: boolean;
|
|
157
|
+
path?: string;
|
|
158
|
+
type?: 'memory' | 'persistent';
|
|
159
|
+
backend?: 'memory' | 'level' | 'indexeddb';
|
|
160
|
+
}
|
|
161
|
+
|
|
154
162
|
export interface ReasonOptions {
|
|
155
163
|
proof?: boolean;
|
|
156
164
|
proofComments?: boolean;
|
|
@@ -158,6 +166,9 @@ declare module 'eyeling' {
|
|
|
158
166
|
args?: string[];
|
|
159
167
|
maxBuffer?: number;
|
|
160
168
|
builtinModules?: string | string[];
|
|
169
|
+
store?: string | StoreOptions;
|
|
170
|
+
storePath?: string;
|
|
171
|
+
storeClear?: boolean;
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
export interface BuiltinRegistrationContext {
|
|
@@ -183,6 +194,9 @@ declare module 'eyeling' {
|
|
|
183
194
|
dataFactory?: RdfJsDataFactory | null;
|
|
184
195
|
skipUnsupportedRdfJs?: boolean;
|
|
185
196
|
builtinModules?: string | string[];
|
|
197
|
+
store?: string | StoreOptions;
|
|
198
|
+
storePath?: string;
|
|
199
|
+
storeClear?: boolean;
|
|
186
200
|
onDerived?: (item: { triple: string; quad?: RdfJsQuad; quads?: RdfJsQuad[]; df: any }) => void;
|
|
187
201
|
}
|
|
188
202
|
|
|
@@ -198,10 +212,45 @@ declare module 'eyeling' {
|
|
|
198
212
|
queryQuads?: RdfJsQuad[];
|
|
199
213
|
}
|
|
200
214
|
|
|
215
|
+
export interface FactStore {
|
|
216
|
+
add(triple: EyelingTriple, kind?: 'explicit' | 'inferred'): Promise<boolean>;
|
|
217
|
+
has(triple: EyelingTriple): Promise<boolean>;
|
|
218
|
+
kindOf?(triple: EyelingTriple): Promise<number>;
|
|
219
|
+
match(s?: EyelingTerm | null, p?: EyelingTerm | null, o?: EyelingTerm | null): AsyncIterable<EyelingTriple>;
|
|
220
|
+
batchAdd?(triples: Iterable<EyelingTriple>, kind?: 'explicit' | 'inferred'): Promise<number>;
|
|
221
|
+
clear?(): Promise<void>;
|
|
222
|
+
close?(): Promise<void>;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export class MemoryFactStore implements FactStore {
|
|
226
|
+
constructor();
|
|
227
|
+
add(triple: EyelingTriple, kind?: 'explicit' | 'inferred'): Promise<boolean>;
|
|
228
|
+
has(triple: EyelingTriple): Promise<boolean>;
|
|
229
|
+
kindOf(triple: EyelingTriple): Promise<number>;
|
|
230
|
+
match(s?: EyelingTerm | null, p?: EyelingTerm | null, o?: EyelingTerm | null): AsyncIterable<EyelingTriple>;
|
|
231
|
+
batchAdd(triples: Iterable<EyelingTriple>, kind?: 'explicit' | 'inferred'): Promise<number>;
|
|
232
|
+
clear(): Promise<void>;
|
|
233
|
+
close(): Promise<void>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export class PersistentFactStore implements FactStore {
|
|
237
|
+
add(triple: EyelingTriple, kind?: 'explicit' | 'inferred'): Promise<boolean>;
|
|
238
|
+
has(triple: EyelingTriple): Promise<boolean>;
|
|
239
|
+
kindOf(triple: EyelingTriple): Promise<number>;
|
|
240
|
+
match(s?: EyelingTerm | null, p?: EyelingTerm | null, o?: EyelingTerm | null): AsyncIterable<EyelingTriple>;
|
|
241
|
+
batchAdd(triples: Iterable<EyelingTriple>, kind?: 'explicit' | 'inferred'): Promise<number>;
|
|
242
|
+
clear(): Promise<void>;
|
|
243
|
+
close(): Promise<void>;
|
|
244
|
+
}
|
|
245
|
+
|
|
201
246
|
export function reason(
|
|
202
247
|
opts: ReasonOptions,
|
|
203
248
|
input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
|
|
204
249
|
): string;
|
|
250
|
+
export function runAsync(
|
|
251
|
+
input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
|
|
252
|
+
opts?: ReasonStreamOptions,
|
|
253
|
+
): Promise<ReasonStreamResult & { store?: FactStore }>;
|
|
205
254
|
export function reasonStream(
|
|
206
255
|
input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
|
|
207
256
|
opts?: ReasonStreamOptions,
|
|
@@ -213,6 +262,7 @@ declare module 'eyeling' {
|
|
|
213
262
|
|
|
214
263
|
export const INFERENCE_FUSE_EXIT_CODE: 65;
|
|
215
264
|
export const rdfjs: RdfJsDataFactory;
|
|
265
|
+
export function createFactStore(options?: string | StoreOptions | null): Promise<FactStore>;
|
|
216
266
|
export function registerBuiltin(iri: string, handler: BuiltinHandler): BuiltinHandler;
|
|
217
267
|
export function unregisterBuiltin(iri: string): boolean;
|
|
218
268
|
export function registerBuiltinModule(mod: any, origin?: string): boolean;
|
|
@@ -230,7 +280,13 @@ declare module 'eyeling/browser' {
|
|
|
230
280
|
export type ReasonStreamOptions = import('eyeling').ReasonStreamOptions;
|
|
231
281
|
export type ReasonStreamResult = import('eyeling').ReasonStreamResult;
|
|
232
282
|
export type BuiltinHandler = import('eyeling').BuiltinHandler;
|
|
283
|
+
export type StoreOptions = import('eyeling').StoreOptions;
|
|
284
|
+
export type FactStore = import('eyeling').FactStore;
|
|
233
285
|
|
|
286
|
+
export function runAsync(
|
|
287
|
+
input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
|
|
288
|
+
opts?: ReasonStreamOptions,
|
|
289
|
+
): Promise<ReasonStreamResult & { store?: FactStore }>;
|
|
234
290
|
export function reasonStream(
|
|
235
291
|
input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
|
|
236
292
|
opts?: ReasonStreamOptions,
|
|
@@ -242,6 +298,7 @@ declare module 'eyeling/browser' {
|
|
|
242
298
|
|
|
243
299
|
export const INFERENCE_FUSE_EXIT_CODE: 65;
|
|
244
300
|
export const rdfjs: RdfJsDataFactory;
|
|
301
|
+
export function createFactStore(options?: string | StoreOptions | null): Promise<FactStore>;
|
|
245
302
|
export function registerBuiltin(iri: string, handler: BuiltinHandler): BuiltinHandler;
|
|
246
303
|
export function unregisterBuiltin(iri: string): boolean;
|
|
247
304
|
export function registerBuiltinModule(mod: any, origin?: string): boolean;
|
|
@@ -249,10 +306,12 @@ declare module 'eyeling/browser' {
|
|
|
249
306
|
|
|
250
307
|
const eyeling: {
|
|
251
308
|
readonly version: string;
|
|
309
|
+
runAsync: typeof runAsync;
|
|
252
310
|
reasonStream: typeof reasonStream;
|
|
253
311
|
reasonRdfJs: typeof reasonRdfJs;
|
|
254
312
|
readonly INFERENCE_FUSE_EXIT_CODE: typeof INFERENCE_FUSE_EXIT_CODE;
|
|
255
313
|
rdfjs: typeof rdfjs;
|
|
314
|
+
createFactStore: typeof createFactStore;
|
|
256
315
|
registerBuiltin: typeof registerBuiltin;
|
|
257
316
|
unregisterBuiltin: typeof unregisterBuiltin;
|
|
258
317
|
registerBuiltinModule: typeof registerBuiltinModule;
|
package/index.js
CHANGED
|
@@ -42,6 +42,15 @@ function reason(opt = {}, input = '') {
|
|
|
42
42
|
|
|
43
43
|
if (opt.rdf) args.push('--rdf');
|
|
44
44
|
|
|
45
|
+
if (typeof opt.store === 'string' && opt.store) args.push('--store', opt.store);
|
|
46
|
+
else if (opt.store && typeof opt.store === 'object') {
|
|
47
|
+
if (opt.store.name) args.push('--store', String(opt.store.name));
|
|
48
|
+
if (opt.store.clear) args.push('--store-clear');
|
|
49
|
+
if (opt.store.path) args.push('--store-path', String(opt.store.path));
|
|
50
|
+
}
|
|
51
|
+
if (opt.storePath) args.push('--store-path', String(opt.storePath));
|
|
52
|
+
if (opt.storeClear) args.push('--store-clear');
|
|
53
|
+
|
|
45
54
|
if (Array.isArray(opt.args)) args.push(...opt.args);
|
|
46
55
|
|
|
47
56
|
const builtinModules = Array.isArray(opt.builtinModules)
|
|
@@ -106,8 +115,13 @@ function reason(opt = {}, input = '') {
|
|
|
106
115
|
}
|
|
107
116
|
}
|
|
108
117
|
|
|
118
|
+
async function runAsync(input = '', opt = {}) {
|
|
119
|
+
return engine.runAsync(input, opt || {});
|
|
120
|
+
}
|
|
121
|
+
|
|
109
122
|
module.exports = {
|
|
110
123
|
reason,
|
|
124
|
+
runAsync,
|
|
111
125
|
reasonStream: bundleApi.reasonStream,
|
|
112
126
|
reasonRdfJs: bundleApi.reasonRdfJs,
|
|
113
127
|
rdfjs: dataFactory,
|
|
@@ -116,6 +130,9 @@ module.exports = {
|
|
|
116
130
|
registerBuiltinModule: engine.registerBuiltinModule,
|
|
117
131
|
loadBuiltinModule: engine.loadBuiltinModule,
|
|
118
132
|
listBuiltinIris: engine.listBuiltinIris,
|
|
133
|
+
createFactStore: engine.createFactStore,
|
|
134
|
+
MemoryFactStore: engine.MemoryFactStore,
|
|
135
|
+
PersistentFactStore: engine.PersistentFactStore,
|
|
119
136
|
};
|
|
120
137
|
|
|
121
138
|
// small interop nicety for ESM default import
|
package/lib/cli.js
CHANGED
|
@@ -562,10 +562,12 @@ function runParsedDocumentOnce(mergedDocument, { rdfMode = false, outputPrefixes
|
|
|
562
562
|
|
|
563
563
|
let derived = [];
|
|
564
564
|
let outTriples = [];
|
|
565
|
+
let queryDerived = [];
|
|
565
566
|
if (hasQueries) {
|
|
566
567
|
const res = engine.forwardChainAndCollectLogQueryConclusions(facts, frules, brules, qrules, { prefixes });
|
|
567
568
|
derived = res.derived;
|
|
568
569
|
outTriples = res.queryTriples;
|
|
570
|
+
queryDerived = res.queryDerived || [];
|
|
569
571
|
} else {
|
|
570
572
|
const skipDerivedCollection = mayAutoRenderOutputStrings;
|
|
571
573
|
derived = engine.forwardChain(facts, frules, brules, null, {
|
|
@@ -579,7 +581,7 @@ function runParsedDocumentOnce(mergedDocument, { rdfMode = false, outputPrefixes
|
|
|
579
581
|
const renderedOutputTriples = hasQueries ? outTriples : facts;
|
|
580
582
|
if (factsContainOutputStrings(renderedOutputTriples)) {
|
|
581
583
|
process.stdout.write(engine.collectOutputStringsFromFacts(renderedOutputTriples, prefixes));
|
|
582
|
-
return;
|
|
584
|
+
return { facts, derived, outTriples, queryDerived, queryMode: !!hasQueries };
|
|
583
585
|
}
|
|
584
586
|
|
|
585
587
|
const outPrefixEnv = outputPrefixes || prefixes;
|
|
@@ -591,9 +593,99 @@ function runParsedDocumentOnce(mergedDocument, { rdfMode = false, outputPrefixes
|
|
|
591
593
|
} else {
|
|
592
594
|
for (const df of derived) console.log(engine.tripleToN3(df.fact, outPrefixEnv));
|
|
593
595
|
}
|
|
596
|
+
return { facts, derived, outTriples, queryDerived, queryMode: !!hasQueries };
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async function createCliStore({ storeName, storePath = null, storeClear = false } = {}) {
|
|
600
|
+
if (!storeName) return null;
|
|
601
|
+
return engine.createFactStore({ name: storeName, path: storePath || undefined, clear: !!storeClear });
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
async function persistRunResultToStore(store, runResult) {
|
|
605
|
+
if (!store || !runResult) return;
|
|
606
|
+
await store.batchAdd(runResult.facts || [], 'explicit');
|
|
607
|
+
await store.batchAdd((runResult.derived || []).map((df) => df.fact), 'inferred');
|
|
608
|
+
await store.batchAdd((runResult.queryDerived || []).map((df) => df.fact), 'inferred');
|
|
609
|
+
await store.batchAdd(runResult.outTriples || [], 'inferred');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
function sourceLooksLikeLineBasedRdf(sourceLabel) {
|
|
613
|
+
if (typeof sourceLabel !== 'string') return false;
|
|
614
|
+
const clean = sourceLabel.split(/[?#]/, 1)[0].toLowerCase();
|
|
615
|
+
return /\.(?:nt|nq)(?:\.gz|\.br|\.deflate)?$/.test(clean);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function parseLineBasedRdfLine(line, { sourceLabel, lineNumber, rdfMode }) {
|
|
619
|
+
const text = String(line || '');
|
|
620
|
+
if (!text.trim() || /^\s*#/.test(text)) return [];
|
|
621
|
+
const doc = parseN3Text(text, {
|
|
622
|
+
baseIri: __sourceLabelToBaseIri(sourceLabel),
|
|
623
|
+
label: `${sourceLabel}:${lineNumber}`,
|
|
624
|
+
keepSourceArtifacts: false,
|
|
625
|
+
sourceLocations: false,
|
|
626
|
+
rdf: rdfMode,
|
|
627
|
+
});
|
|
628
|
+
return doc.triples || [];
|
|
594
629
|
}
|
|
595
630
|
|
|
596
|
-
async function
|
|
631
|
+
async function ingestLineBasedRdfSourceToStore(sourceLabel, store, { rdfMode = true } = {}) {
|
|
632
|
+
let lineNumber = 0;
|
|
633
|
+
let count = 0;
|
|
634
|
+
const onLine = async (line) => {
|
|
635
|
+
lineNumber += 1;
|
|
636
|
+
let triples;
|
|
637
|
+
try {
|
|
638
|
+
triples = parseLineBasedRdfLine(line, { sourceLabel, lineNumber, rdfMode });
|
|
639
|
+
} catch (e) {
|
|
640
|
+
if (e && e.name === 'N3SyntaxError') {
|
|
641
|
+
throw new Error(formatN3SyntaxError(e, line, `${sourceLabel}:${lineNumber}`));
|
|
642
|
+
}
|
|
643
|
+
throw e;
|
|
644
|
+
}
|
|
645
|
+
count += await store.batchAdd(triples, 'explicit');
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
const filePath = __localPathForSource(sourceLabel);
|
|
649
|
+
if (filePath) {
|
|
650
|
+
const fd = fs.openSync(filePath, 'r');
|
|
651
|
+
const decoder = new TextDecoder('utf8');
|
|
652
|
+
const buf = Buffer.allocUnsafe(64 * 1024);
|
|
653
|
+
let carry = '';
|
|
654
|
+
try {
|
|
655
|
+
for (;;) {
|
|
656
|
+
const n = fs.readSync(fd, buf, 0, buf.length, null);
|
|
657
|
+
if (n === 0) break;
|
|
658
|
+
carry += decoder.decode(buf.subarray(0, n), { stream: true });
|
|
659
|
+
for (;;) {
|
|
660
|
+
const m = /\r\n|\n|\r/.exec(carry);
|
|
661
|
+
if (!m) break;
|
|
662
|
+
const end = m.index + m[0].length;
|
|
663
|
+
await onLine(carry.slice(0, end));
|
|
664
|
+
carry = carry.slice(end);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
carry += decoder.decode();
|
|
668
|
+
if (carry) await onLine(carry);
|
|
669
|
+
} finally {
|
|
670
|
+
fs.closeSync(fd);
|
|
671
|
+
}
|
|
672
|
+
return count;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if (__isHttpSource(sourceLabel)) {
|
|
676
|
+
const body = await __openHttpTextStream(sourceLabel);
|
|
677
|
+
const rl = readline.createInterface({ input: body, crlfDelay: Infinity });
|
|
678
|
+
for await (const line of rl) await onLine(line + '\n');
|
|
679
|
+
return count;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const text = __readInputSourceSync(sourceLabel);
|
|
683
|
+
for (const line of text.match(/.*(?:\r\n|\n|\r)|.+$/g) || []) await onLine(line);
|
|
684
|
+
return count;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
async function runStreamMessagesMode(sourceLabels, { rdfMode, storeName = null, storePath = null, storeClear = false } = {}) {
|
|
597
689
|
const ordinarySourceLabels = [];
|
|
598
690
|
const messageSourceLabels = [];
|
|
599
691
|
|
|
@@ -642,40 +734,49 @@ async function runStreamMessagesMode(sourceLabels, { rdfMode }) {
|
|
|
642
734
|
}
|
|
643
735
|
}
|
|
644
736
|
|
|
737
|
+
const store = await createCliStore({ storeName, storePath, storeClear });
|
|
738
|
+
let pendingStoreWrites = Promise.resolve();
|
|
739
|
+
|
|
645
740
|
const fullIriPrefixes = new PrefixEnv({});
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
let messageDoc;
|
|
656
|
-
try {
|
|
657
|
-
messageDoc = parseN3Text(messageText, {
|
|
658
|
-
baseIri: `${__sourceLabelToBaseIri(messageSourceLabel)}#message-${messageIndex}`,
|
|
659
|
-
label: `${messageSourceLabel}#message-${messageIndex}`,
|
|
660
|
-
keepSourceArtifacts: false,
|
|
661
|
-
sourceLocations: false,
|
|
662
|
-
rdf: false,
|
|
741
|
+
try {
|
|
742
|
+
for (const messageSourceLabel of messageSourceLabels) {
|
|
743
|
+
try {
|
|
744
|
+
await __forEachRdfMessageChunk(messageSourceLabel, ({ messageIndex, chunk, directives }) => {
|
|
745
|
+
const messageText = buildSingleMessageReplayDocument({
|
|
746
|
+
sourceLabel: messageSourceLabel,
|
|
747
|
+
messageIndex,
|
|
748
|
+
chunk,
|
|
749
|
+
directives,
|
|
663
750
|
});
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
751
|
+
let messageDoc;
|
|
752
|
+
try {
|
|
753
|
+
messageDoc = parseN3Text(messageText, {
|
|
754
|
+
baseIri: `${__sourceLabelToBaseIri(messageSourceLabel)}#message-${messageIndex}`,
|
|
755
|
+
label: `${messageSourceLabel}#message-${messageIndex}`,
|
|
756
|
+
keepSourceArtifacts: false,
|
|
757
|
+
sourceLocations: false,
|
|
758
|
+
rdf: false,
|
|
759
|
+
});
|
|
760
|
+
} catch (e) {
|
|
761
|
+
if (e && e.name === 'N3SyntaxError') {
|
|
762
|
+
console.error(formatN3SyntaxError(e, messageText, `${messageSourceLabel}#message-${messageIndex}`));
|
|
763
|
+
process.exit(1);
|
|
764
|
+
}
|
|
765
|
+
throw e;
|
|
668
766
|
}
|
|
669
|
-
throw e;
|
|
670
|
-
}
|
|
671
767
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
768
|
+
const merged = mergeParsedDocuments(programSources.concat([messageDoc]));
|
|
769
|
+
const result = runParsedDocumentOnce(merged, { rdfMode, outputPrefixes: fullIriPrefixes });
|
|
770
|
+
if (store) pendingStoreWrites = pendingStoreWrites.then(() => persistRunResultToStore(store, result));
|
|
771
|
+
});
|
|
772
|
+
} catch (e) {
|
|
773
|
+
console.error(`Error streaming RDF Message Log ${JSON.stringify(messageSourceLabel)}: ${e && e.message ? e.message : String(e)}`);
|
|
774
|
+
process.exit(1);
|
|
775
|
+
}
|
|
678
776
|
}
|
|
777
|
+
await pendingStoreWrites;
|
|
778
|
+
} finally {
|
|
779
|
+
if (store && typeof store.close === 'function') await store.close();
|
|
679
780
|
}
|
|
680
781
|
}
|
|
681
782
|
|
|
@@ -710,6 +811,9 @@ async function main() {
|
|
|
710
811
|
` -p, --proof Enable proof explanations.\n` +
|
|
711
812
|
` -r, --rdf Enable RDF/TriG input/output compatibility.\n` +
|
|
712
813
|
` --stream-messages Process RDF Message Logs one message at a time under -r.\n` +
|
|
814
|
+
` --store <name> Use an optional persistent fact store.\n` +
|
|
815
|
+
` --store-clear Clear the named store before this run.\n` +
|
|
816
|
+
` --store-path <dir> Node.js persistent store directory.\n` +
|
|
713
817
|
` -s, --super-restricted Disable all builtins except => and <=.\n` +
|
|
714
818
|
` -t, --stream Stream derived triples as soon as they are derived.\n` +
|
|
715
819
|
` -v, --version Print version and exit.\n`;
|
|
@@ -746,6 +850,35 @@ async function main() {
|
|
|
746
850
|
builtinModules.push(a.slice('--builtin='.length));
|
|
747
851
|
continue;
|
|
748
852
|
}
|
|
853
|
+
if (a === '--store') {
|
|
854
|
+
const next = argv[i + 1];
|
|
855
|
+
if (!next || next.startsWith('-')) {
|
|
856
|
+
console.error('Error: --store expects a store name.');
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
859
|
+
argv.__storeName = next;
|
|
860
|
+
i += 1;
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
if (typeof a === 'string' && a.startsWith('--store=')) {
|
|
864
|
+
argv.__storeName = a.slice('--store='.length);
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
if (a === '--store-path') {
|
|
868
|
+
const next = argv[i + 1];
|
|
869
|
+
if (!next || next.startsWith('-')) {
|
|
870
|
+
console.error('Error: --store-path expects a directory path.');
|
|
871
|
+
process.exit(1);
|
|
872
|
+
}
|
|
873
|
+
argv.__storePath = next;
|
|
874
|
+
i += 1;
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
if (typeof a === 'string' && a.startsWith('--store-path=')) {
|
|
878
|
+
argv.__storePath = a.slice('--store-path='.length);
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
if (a === '--store-clear') continue;
|
|
749
882
|
if (a === '-' || !a.startsWith('-')) positional.push(a);
|
|
750
883
|
}
|
|
751
884
|
|
|
@@ -753,6 +886,9 @@ async function main() {
|
|
|
753
886
|
const streamMode = argv.includes('--stream') || argv.includes('-t');
|
|
754
887
|
const streamMessagesMode = argv.includes('--stream-messages');
|
|
755
888
|
const rdfMode = argv.includes('--rdf') || argv.includes('-r');
|
|
889
|
+
const storeName = argv.__storeName || null;
|
|
890
|
+
const storePath = argv.__storePath || null;
|
|
891
|
+
const storeClear = argv.includes('--store-clear');
|
|
756
892
|
|
|
757
893
|
// --enforce-https: rewrite http:// -> https:// for log dereferencing builtins
|
|
758
894
|
if (argv.includes('--enforce-https') || argv.includes('-e')) {
|
|
@@ -811,17 +947,94 @@ async function main() {
|
|
|
811
947
|
}
|
|
812
948
|
}
|
|
813
949
|
|
|
814
|
-
|
|
950
|
+
let sourceLabels = useImplicitStdin ? ['<stdin>'] : positional.map((item) => (item === '-' ? '<stdin>' : item));
|
|
815
951
|
if (sourceLabels.filter((item) => item === '<stdin>').length > 1) {
|
|
816
952
|
console.error('Error: stdin can only be used once.');
|
|
817
953
|
process.exit(1);
|
|
818
954
|
}
|
|
819
955
|
|
|
820
956
|
if (streamMessagesMode) {
|
|
821
|
-
await runStreamMessagesMode(sourceLabels, { rdfMode });
|
|
957
|
+
await runStreamMessagesMode(sourceLabels, { rdfMode, storeName, storePath, storeClear });
|
|
822
958
|
return;
|
|
823
959
|
}
|
|
824
960
|
|
|
961
|
+
if (storeName && rdfMode) {
|
|
962
|
+
const lineBasedSources = sourceLabels.filter(sourceLooksLikeLineBasedRdf);
|
|
963
|
+
if (lineBasedSources.length) {
|
|
964
|
+
if (showAst) {
|
|
965
|
+
console.error('Error: line-based --store ingestion cannot be combined with --ast.');
|
|
966
|
+
process.exit(1);
|
|
967
|
+
}
|
|
968
|
+
if (streamMode) {
|
|
969
|
+
console.error('Error: line-based --store ingestion cannot be combined with --stream.');
|
|
970
|
+
process.exit(1);
|
|
971
|
+
}
|
|
972
|
+
if (engine.getProofCommentsEnabled()) {
|
|
973
|
+
console.error('Error: line-based --store ingestion currently does not support proof output.');
|
|
974
|
+
process.exit(1);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
const store = await createCliStore({ storeName, storePath, storeClear });
|
|
978
|
+
try {
|
|
979
|
+
for (const sourceLabel of lineBasedSources) {
|
|
980
|
+
try {
|
|
981
|
+
await ingestLineBasedRdfSourceToStore(sourceLabel, store, { rdfMode });
|
|
982
|
+
} catch (e) {
|
|
983
|
+
console.error(`Error streaming RDF source ${JSON.stringify(sourceLabel)}: ${e && e.message ? e.message : String(e)}`);
|
|
984
|
+
process.exit(1);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
sourceLabels = sourceLabels.filter((sourceLabel) => !sourceLooksLikeLineBasedRdf(sourceLabel));
|
|
989
|
+
if (!sourceLabels.length) return;
|
|
990
|
+
|
|
991
|
+
const parsedRuleSources = [];
|
|
992
|
+
for (const sourceLabel of sourceLabels) {
|
|
993
|
+
let text;
|
|
994
|
+
try {
|
|
995
|
+
text = __readInputSourceSync(sourceLabel);
|
|
996
|
+
} catch (e) {
|
|
997
|
+
if (sourceLabel === '<stdin>') console.error(`Error reading stdin: ${e.message}`);
|
|
998
|
+
else console.error(`Error reading source ${JSON.stringify(sourceLabel)}: ${e.message}`);
|
|
999
|
+
process.exit(1);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
try {
|
|
1003
|
+
parsedRuleSources.push(
|
|
1004
|
+
parseN3Text(text, {
|
|
1005
|
+
baseIri: __sourceLabelToBaseIri(sourceLabel),
|
|
1006
|
+
label: sourceLabel,
|
|
1007
|
+
collectUsedPrefixes: false,
|
|
1008
|
+
keepSourceArtifacts: false,
|
|
1009
|
+
sourceLocations: false,
|
|
1010
|
+
rdf: rdfMode,
|
|
1011
|
+
}),
|
|
1012
|
+
);
|
|
1013
|
+
} catch (e) {
|
|
1014
|
+
if (e && e.name === 'N3SyntaxError') {
|
|
1015
|
+
console.error(formatN3SyntaxError(e, text, sourceLabel));
|
|
1016
|
+
process.exit(1);
|
|
1017
|
+
}
|
|
1018
|
+
throw e;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
const mergedRuleDocument = mergeParsedDocuments(parsedRuleSources);
|
|
1023
|
+
const result = await engine.runStoreBacked(mergedRuleDocument, store, { rdf: rdfMode });
|
|
1024
|
+
const outTriples = result.queryMode ? result.queryTriples || [] : (result.derived || []).map((df) => df.fact);
|
|
1025
|
+
if (result.queryMode) {
|
|
1026
|
+
const bodyText = engine.prettyPrintQueryTriples(outTriples, result.prefixes);
|
|
1027
|
+
if (bodyText) process.stdout.write(String(bodyText).replace(/\s*$/g, '') + '\n');
|
|
1028
|
+
} else {
|
|
1029
|
+
for (const tr of outTriples) console.log(engine.tripleToRdfCompatible(tr, result.prefixes));
|
|
1030
|
+
}
|
|
1031
|
+
return;
|
|
1032
|
+
} finally {
|
|
1033
|
+
if (store && typeof store.close === 'function') await store.close();
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
825
1038
|
const parsedSources = [];
|
|
826
1039
|
for (const sourceLabel of sourceLabels) {
|
|
827
1040
|
let text;
|
|
@@ -931,6 +1144,69 @@ function factsContainOutputStrings(triplesForOutput) {
|
|
|
931
1144
|
const hasQueries = Array.isArray(qrules) && qrules.length;
|
|
932
1145
|
const mayAutoRenderOutputStrings = programMayProduceOutputStrings(triples, frules, qrules);
|
|
933
1146
|
|
|
1147
|
+
if (storeName) {
|
|
1148
|
+
if (streamMode) {
|
|
1149
|
+
console.error('Error: --store cannot be combined with --stream yet.');
|
|
1150
|
+
process.exit(1);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const storeResult = await engine.runAsync(
|
|
1154
|
+
{ prefixes, triples, frules, brules, logQueryRules: qrules },
|
|
1155
|
+
{
|
|
1156
|
+
proof: engine.getProofCommentsEnabled(),
|
|
1157
|
+
rdf: rdfMode,
|
|
1158
|
+
store: { name: storeName, clear: storeClear, path: storePath || undefined },
|
|
1159
|
+
},
|
|
1160
|
+
);
|
|
1161
|
+
|
|
1162
|
+
const storeFacts = storeResult.facts || [];
|
|
1163
|
+
const storeDerived = storeResult.derived || [];
|
|
1164
|
+
const storeHasQueries = !!storeResult.queryMode;
|
|
1165
|
+
const storeOutTriples = storeHasQueries ? (storeResult.queryTriples || []) : (mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled() ? [] : storeDerived.map((df) => df.fact));
|
|
1166
|
+
const storeOutDerived = storeHasQueries ? (storeResult.queryDerived || []) : storeDerived;
|
|
1167
|
+
const renderedOutputTriples = storeHasQueries ? storeOutTriples : storeFacts;
|
|
1168
|
+
|
|
1169
|
+
if (factsContainOutputStrings(renderedOutputTriples)) {
|
|
1170
|
+
process.stdout.write(engine.collectOutputStringsFromFacts(renderedOutputTriples, prefixes));
|
|
1171
|
+
if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if (engine.getProofCommentsEnabled()) {
|
|
1176
|
+
process.stdout.write(engine.renderProofDocument(storeOutDerived, storeDerived.concat(storeOutDerived || []), triples, prefixes, brules));
|
|
1177
|
+
if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
let bodyText = '';
|
|
1182
|
+
if (rdfMode) bodyText = storeOutTriples.map((tr) => engine.tripleToRdfCompatible(tr, prefixes)).join('\n');
|
|
1183
|
+
else if (storeHasQueries) bodyText = engine.prettyPrintQueryTriples(storeOutTriples, prefixes);
|
|
1184
|
+
|
|
1185
|
+
let usedPrefixes = prefixes.prefixesUsedForOutput(storeOutTriples);
|
|
1186
|
+
if (rdfMode && bodyText) usedPrefixes = usedPrefixes.filter(([pfx]) => pfx === '' || bodyText.includes(pfx + ':'));
|
|
1187
|
+
|
|
1188
|
+
if (rdfMode && bodyText.includes('<<(')) {
|
|
1189
|
+
console.log('VERSION "1.2"');
|
|
1190
|
+
console.log();
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
for (const [pfx, base] of usedPrefixes) {
|
|
1194
|
+
if (pfx === '') console.log(`@prefix : <${base}> .`);
|
|
1195
|
+
else console.log(`@prefix ${pfx}: <${base}> .`);
|
|
1196
|
+
}
|
|
1197
|
+
if (storeOutTriples.length && usedPrefixes.length) console.log();
|
|
1198
|
+
|
|
1199
|
+
if (bodyText) process.stdout.write(String(bodyText).replace(/\s*$/g, '') + '\n');
|
|
1200
|
+
else {
|
|
1201
|
+
for (const df of storeOutDerived) {
|
|
1202
|
+
console.log(rdfMode ? engine.tripleToRdfCompatible(df.fact, prefixes) : engine.tripleToN3(df.fact, prefixes));
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
934
1210
|
if (streamMode && !hasQueries && !mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled()) {
|
|
935
1211
|
const usedInInput = mergedDocument.usedPrefixes instanceof Set ? new Set(mergedDocument.usedPrefixes) : new Set();
|
|
936
1212
|
const outPrefixes = restrictPrefixEnv(prefixes, usedInInput);
|